Text Generation
Transformers
Safetensors
code
fela
fourier-neural-operator
fno
gated-deltanet
cpu
on-device
autocomplete
fill-in-the-middle
constant-memory
custom_code
Eval Results (legacy)
Instructions to use lowdown-labs/fela-autocomplete with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use lowdown-labs/fela-autocomplete with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="lowdown-labs/fela-autocomplete", trust_remote_code=True)# Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("lowdown-labs/fela-autocomplete", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use lowdown-labs/fela-autocomplete with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "lowdown-labs/fela-autocomplete" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "lowdown-labs/fela-autocomplete", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/lowdown-labs/fela-autocomplete
- SGLang
How to use lowdown-labs/fela-autocomplete with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "lowdown-labs/fela-autocomplete" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "lowdown-labs/fela-autocomplete", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "lowdown-labs/fela-autocomplete" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "lowdown-labs/fela-autocomplete", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use lowdown-labs/fela-autocomplete with Docker Model Runner:
docker model run hf.co/lowdown-labs/fela-autocomplete
Commit ·
309d916
0
Parent(s):
initial commit
Browse files- .gitattributes +1 -0
- .gitignore +6 -0
- LICENSE +474 -0
- README.md +285 -0
- config.json +40 -0
- configuration_fela.py +43 -0
- cpu_delta.py +256 -0
- cpu_landmark.py +99 -0
- cpu_patch.py +157 -0
- cpu_swa.py +89 -0
- model.safetensors +3 -0
- model_cpu_gpt2.py +1262 -0
- model_int8.safetensors +3 -0
- modeling.py +230 -0
- modeling_fela.py +84 -0
- quickstart/README.md +47 -0
- quickstart/requirements.txt +5 -0
- quickstart/run.py +44 -0
- requirements.txt +5 -0
- space/README.md +28 -0
- space/app.py +44 -0
- space/requirements.txt +6 -0
- tokenizer.json +0 -0
- verify.py +39 -0
.gitattributes
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.ruff_cache/
|
| 2 |
+
.venv/
|
| 3 |
+
__pycache__/
|
| 4 |
+
*.swp
|
| 5 |
+
*.kate-swp
|
| 6 |
+
*~
|
LICENSE
ADDED
|
@@ -0,0 +1,474 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Lowdown Labs Lovely License 1.0 (LLLL-1.0)
|
| 2 |
+
|
| 3 |
+
Everything in this repository (the model weights, the configuration, and the code) is
|
| 4 |
+
released by Lowdown Labs under two licenses that apply at the same time. To use this work
|
| 5 |
+
you must comply with BOTH of them. Where a term in one is stricter than the other, the
|
| 6 |
+
stricter term controls. "Lowdown Labs Lovely License 1.0" is a convenience name for this
|
| 7 |
+
exact pair; it is not a new legal instrument.
|
| 8 |
+
|
| 9 |
+
SPDX-License-Identifier: CC-BY-NC-4.0 AND LicenseRef-Hippocratic-3.0
|
| 10 |
+
|
| 11 |
+
Commercial licensing. The grant below is non-commercial only. Commercial licenses are
|
| 12 |
+
sold separately by Lowdown Labs on a per-customer basis. To use this work, its weights, or
|
| 13 |
+
its outputs for any commercial purpose, contact Lowdown Labs to purchase a commercial
|
| 14 |
+
license. A commercial license does not remove the Hippocratic ethical-use obligations in
|
| 15 |
+
Part 2; those apply to commercial licensees as well.
|
| 16 |
+
|
| 17 |
+
==============================================================================
|
| 18 |
+
Part 1 of 2. Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0)
|
| 19 |
+
==============================================================================
|
| 20 |
+
|
| 21 |
+
You may share and adapt this work for non-commercial purposes, with attribution to
|
| 22 |
+
Lowdown Labs. Commercial use is not granted under this license.
|
| 23 |
+
|
| 24 |
+
Full legal text: https://creativecommons.org/licenses/by-nc/4.0/legalcode
|
| 25 |
+
Plain-language summary: https://creativecommons.org/licenses/by-nc/4.0/
|
| 26 |
+
SPDX-License-Identifier: CC-BY-NC-4.0
|
| 27 |
+
|
| 28 |
+
==============================================================================
|
| 29 |
+
Part 2 of 2. The Hippocratic License 3.0 (ethical use)
|
| 30 |
+
==============================================================================
|
| 31 |
+
|
| 32 |
+
Module set enabled: bds, cl, eco, extr, ffd, law, media, mil, my, soc, sup, sv, usta.
|
| 33 |
+
Canonical build: https://firstdonoharm.dev/build/?modules=bds,cl,eco,extr,ffd,law,media,mil,my,soc,sup,sv,usta
|
| 34 |
+
|
| 35 |
+
The verbatim official Hippocratic License 3.0 text for exactly this module set follows,
|
| 36 |
+
between the markers.
|
| 37 |
+
|
| 38 |
+
--------------------- BEGIN OFFICIAL HIPPOCRATIC LICENSE 3.0 TEXT ---------------------
|
| 39 |
+
|
| 40 |
+
HIPPOCRATIC LICENSE
|
| 41 |
+
|
| 42 |
+
Version 3.0, October 2021
|
| 43 |
+
|
| 44 |
+
https://firstdonoharm.dev/version/3/0/bds-cl-eco-extr-ffd-law-media-mil-my-soc-sup-sv-usta.txt
|
| 45 |
+
|
| 46 |
+
TERMS AND CONDITIONS
|
| 47 |
+
|
| 48 |
+
TERMS AND CONDITIONS FOR USE, COPY, MODIFICATION, PREPARATION OF DERIVATIVE
|
| 49 |
+
WORK, REPRODUCTION, AND DISTRIBUTION:
|
| 50 |
+
|
| 51 |
+
1. DEFINITIONS:
|
| 52 |
+
|
| 53 |
+
This section defines certain terms used throughout this license agreement.
|
| 54 |
+
|
| 55 |
+
1.1. “License” means the terms and conditions, as stated herein, for use, copy,
|
| 56 |
+
modification, preparation of derivative work, reproduction, and distribution of
|
| 57 |
+
Software (as defined below).
|
| 58 |
+
|
| 59 |
+
1.2. “Licensor” means the copyright and/or patent owner or entity authorized by
|
| 60 |
+
the copyright and/or patent owner that is granting the License.
|
| 61 |
+
|
| 62 |
+
1.3. “Licensee” means the individual or entity exercising permissions granted by
|
| 63 |
+
this License, including the use, copy, modification, preparation of derivative
|
| 64 |
+
work, reproduction, and distribution of Software (as defined below).
|
| 65 |
+
|
| 66 |
+
1.4. “Software” means any copyrighted work, including but not limited to
|
| 67 |
+
software code, authored by Licensor and made available under this License.
|
| 68 |
+
|
| 69 |
+
1.5. “Supply Chain” means the sequence of processes involved in the production
|
| 70 |
+
and/or distribution of a commodity, good, or service offered by the Licensee.
|
| 71 |
+
|
| 72 |
+
1.6. “Supply Chain Impacted Party” or “Supply Chain Impacted Parties” means any
|
| 73 |
+
person(s) directly impacted by any of Licensee’s Supply Chain, including the
|
| 74 |
+
practices of all persons or entities within the Supply Chain prior to a good or
|
| 75 |
+
service reaching the Licensee.
|
| 76 |
+
|
| 77 |
+
1.7. “Duty of Care” is defined by its use in tort law, delict law, and/or
|
| 78 |
+
similar bodies of law closely related to tort and/or delict law, including
|
| 79 |
+
without limitation, a requirement to act with the watchfulness, attention,
|
| 80 |
+
caution, and prudence that a reasonable person in the same or similar
|
| 81 |
+
circumstances would use towards any Supply Chain Impacted Party.
|
| 82 |
+
|
| 83 |
+
1.8. “Worker” is defined to include any and all permanent, temporary, and agency
|
| 84 |
+
workers, as well as piece-rate, salaried, hourly paid, legal young (minors),
|
| 85 |
+
part-time, night, and migrant workers.
|
| 86 |
+
|
| 87 |
+
2. INTELLECTUAL PROPERTY GRANTS:
|
| 88 |
+
|
| 89 |
+
This section identifies intellectual property rights granted to a Licensee.
|
| 90 |
+
|
| 91 |
+
2.1. Grant of Copyright License: Subject to the terms and conditions of this
|
| 92 |
+
License, Licensor hereby grants to Licensee a worldwide, non-exclusive,
|
| 93 |
+
no-charge, royalty-free copyright license to use, copy, modify, prepare
|
| 94 |
+
derivative work, reproduce, or distribute the Software, Licensor authored
|
| 95 |
+
modified software, or other work derived from the Software.
|
| 96 |
+
|
| 97 |
+
2.2. Grant of Patent License: Subject to the terms and conditions of this
|
| 98 |
+
License, Licensor hereby grants Licensee a worldwide, non-exclusive, no-charge,
|
| 99 |
+
royalty-free patent license to make, have made, use, offer to sell, sell,
|
| 100 |
+
import, and otherwise transfer Software.
|
| 101 |
+
|
| 102 |
+
3. ETHICAL STANDARDS:
|
| 103 |
+
|
| 104 |
+
This section lists conditions the Licensee must comply with in order to have
|
| 105 |
+
rights under this License.
|
| 106 |
+
|
| 107 |
+
The rights granted to the Licensee by this License are expressly made subject to
|
| 108 |
+
the Licensee’s ongoing compliance with the following conditions:
|
| 109 |
+
|
| 110 |
+
* 3.1. The Licensee SHALL NOT, whether directly or indirectly, through agents
|
| 111 |
+
or assigns:
|
| 112 |
+
|
| 113 |
+
* 3.1.1. Infringe upon any person’s right to life or security of person,
|
| 114 |
+
engage in extrajudicial killings, or commit murder, without lawful cause
|
| 115 |
+
(See Article 3, United Nations Universal Declaration of Human Rights;
|
| 116 |
+
Article 6, International Covenant on Civil and Political Rights)
|
| 117 |
+
|
| 118 |
+
* 3.1.2. Hold any person in slavery, servitude, or forced labor (See Article
|
| 119 |
+
4, United Nations Universal Declaration of Human Rights; Article 8,
|
| 120 |
+
International Covenant on Civil and Political Rights);
|
| 121 |
+
|
| 122 |
+
* 3.1.3. Contribute to the institution of slavery, slave trading, forced
|
| 123 |
+
labor, or unlawful child labor (See Article 4, United Nations Universal
|
| 124 |
+
Declaration of Human Rights; Article 8, International Covenant on Civil and
|
| 125 |
+
Political Rights);
|
| 126 |
+
|
| 127 |
+
* 3.1.4. Torture or subject any person to cruel, inhumane, or degrading
|
| 128 |
+
treatment or punishment (See Article 5, United Nations Universal
|
| 129 |
+
Declaration of Human Rights; Article 7, International Covenant on Civil and
|
| 130 |
+
Political Rights);
|
| 131 |
+
|
| 132 |
+
* 3.1.5. Discriminate on the basis of sex, gender, sexual orientation, race,
|
| 133 |
+
ethnicity, nationality, religion, caste, age, medical disability or
|
| 134 |
+
impairment, and/or any other like circumstances (See Article 7, United
|
| 135 |
+
Nations Universal Declaration of Human Rights; Article 2, International
|
| 136 |
+
Covenant on Economic, Social and Cultural Rights; Article 26, International
|
| 137 |
+
Covenant on Civil and Political Rights);
|
| 138 |
+
|
| 139 |
+
* 3.1.6. Prevent any person from exercising his/her/their right to seek an
|
| 140 |
+
effective remedy by a competent court or national tribunal (including
|
| 141 |
+
domestic judicial systems, international courts, arbitration bodies, and
|
| 142 |
+
other adjudicating bodies) for actions violating the fundamental rights
|
| 143 |
+
granted to him/her/them by applicable constitutions, applicable laws, or by
|
| 144 |
+
this License (See Article 8, United Nations Universal Declaration of Human
|
| 145 |
+
Rights; Articles 9 and 14, International Covenant on Civil and Political
|
| 146 |
+
Rights);
|
| 147 |
+
|
| 148 |
+
* 3.1.7. Subject any person to arbitrary arrest, detention, or exile (See
|
| 149 |
+
Article 9, United Nations Universal Declaration of Human Rights; Article 9,
|
| 150 |
+
International Covenant on Civil and Political Rights);
|
| 151 |
+
|
| 152 |
+
* 3.1.8. Subject any person to arbitrary interference with a person’s
|
| 153 |
+
privacy, family, home, or correspondence without the express written
|
| 154 |
+
consent of the person (See Article 12, United Nations Universal Declaration
|
| 155 |
+
of Human Rights; Article 17, International Covenant on Civil and Political
|
| 156 |
+
Rights);
|
| 157 |
+
|
| 158 |
+
* 3.1.9. Arbitrarily deprive any person of his/her/their property (See
|
| 159 |
+
Article 17, United Nations Universal Declaration of Human Rights);
|
| 160 |
+
|
| 161 |
+
* 3.1.10. Forcibly remove indigenous peoples from their lands or territories
|
| 162 |
+
or take any action with the aim or effect of dispossessing indigenous
|
| 163 |
+
peoples from their lands, territories, or resources, including without
|
| 164 |
+
limitation the intellectual property or traditional knowledge of indigenous
|
| 165 |
+
peoples, without the free, prior, and informed consent of indigenous
|
| 166 |
+
peoples concerned (See Articles 8 and 10, United Nations Declaration on the
|
| 167 |
+
Rights of Indigenous Peoples);
|
| 168 |
+
* 3.1.11. Fossil Fuel Divestment: Be an individual or entity, or a
|
| 169 |
+
representative, agent, affiliate, successor, attorney, or assign of an
|
| 170 |
+
individual or entity, on the FFI Solutions Carbon Underground 200 list
|
| 171 |
+
[https://www.ffisolutions.com/research-analytics-index-solutions/research-screening/the-carbon-underground-200/?cn-reloaded=1];
|
| 172 |
+
|
| 173 |
+
* 3.1.12. Ecocide: Commit ecocide:
|
| 174 |
+
|
| 175 |
+
* 3.1.12.1. For the purpose of this section, “ecocide” means unlawful or
|
| 176 |
+
wanton acts committed with knowledge that there is a substantial
|
| 177 |
+
likelihood of severe and either widespread or long-term damage to the
|
| 178 |
+
environment being caused by those acts;
|
| 179 |
+
|
| 180 |
+
* 3.1.12.2. For the purpose of further defining ecocide and the terms
|
| 181 |
+
contained in the previous paragraph:
|
| 182 |
+
|
| 183 |
+
* 3.1.12.2.1. “Wanton” means with reckless disregard for damage which
|
| 184 |
+
would be clearly excessive in relation to the social and economic
|
| 185 |
+
benefits anticipated;
|
| 186 |
+
|
| 187 |
+
* 3.1.12.2.2. “Severe” means damage which involves very serious adverse
|
| 188 |
+
changes, disruption, or harm to any element of the environment,
|
| 189 |
+
including grave impacts on human life or natural, cultural, or
|
| 190 |
+
economic resources;
|
| 191 |
+
|
| 192 |
+
* 3.1.12.2.3. “Widespread” means damage which extends beyond a limited
|
| 193 |
+
geographic area, crosses state boundaries, or is suffered by an entire
|
| 194 |
+
ecosystem or species or a large number of human beings;
|
| 195 |
+
|
| 196 |
+
* 3.1.12.2.4. “Long-term” means damage which is irreversible or which
|
| 197 |
+
cannot be redressed through natural recovery within a reasonable
|
| 198 |
+
period of time; and
|
| 199 |
+
|
| 200 |
+
* 3.1.12.2.5. “Environment” means the earth, its biosphere, cryosphere,
|
| 201 |
+
lithosphere, hydrosphere, and atmosphere, as well as outer space
|
| 202 |
+
|
| 203 |
+
(See Section II, Independent Expert Panel for the Legal Definition of
|
| 204 |
+
Ecocide, Stop Ecocide Foundation and the Promise Institute for Human
|
| 205 |
+
Rights at UCLA School of Law, June 2021);
|
| 206 |
+
|
| 207 |
+
* 3.1.13. Extractive Industries: Be an individual or entity, or a
|
| 208 |
+
representative, agent, affiliate, successor, attorney, or assign of an
|
| 209 |
+
individual or entity, that engages in fossil fuel or mineral exploration,
|
| 210 |
+
extraction, development, or sale;
|
| 211 |
+
|
| 212 |
+
* 3.1.14. Boycott / Divestment / Sanctions: Be an individual or entity, or a
|
| 213 |
+
representative, agent, affiliate, successor, attorney, or assign of an
|
| 214 |
+
individual or entity, identified by the Boycott, Divestment, Sanctions
|
| 215 |
+
(“BDS”) movement on its website (https://bdsmovement.net/
|
| 216 |
+
[https://bdsmovement.net/] and
|
| 217 |
+
https://bdsmovement.net/get-involved/what-to-boycott
|
| 218 |
+
[https://bdsmovement.net/get-involved/what-to-boycott]) as a target for
|
| 219 |
+
boycott;
|
| 220 |
+
|
| 221 |
+
* 3.1.15. Myanmar: Be an individual or entity that:
|
| 222 |
+
|
| 223 |
+
* 3.1.15.1. engages in any commercial transactions with the
|
| 224 |
+
Myanmar/Burmese military junta; or
|
| 225 |
+
|
| 226 |
+
* 3.1.15.2. is a representative, agent, affiliate, successor, attorney, or
|
| 227 |
+
assign of the Myanmar/Burmese government;
|
| 228 |
+
|
| 229 |
+
* 3.1.16. US Tariff Act: Be an individual or entity:
|
| 230 |
+
|
| 231 |
+
* 3.1.16.1. which U.S. Customs and Border Protection (CBP) has currently
|
| 232 |
+
issued a Withhold Release Order (WRO) or finding against based on
|
| 233 |
+
reasonable suspicion of forced labor; or
|
| 234 |
+
|
| 235 |
+
* 3.1.16.2. that is a representative, agent, affiliate, successor,
|
| 236 |
+
attorney, or assign of an individual or entity that does business with
|
| 237 |
+
an individual or entity which currently has a WRO or finding from CBP
|
| 238 |
+
issued against it based on reasonable suspicion of forced labor;
|
| 239 |
+
|
| 240 |
+
* 3.1.17. Mass Surveillance: Be a government agency or multinational
|
| 241 |
+
corporation, or a representative, agent, affiliate, successor, attorney,
|
| 242 |
+
or assign of a government or multinational corporation, which participates
|
| 243 |
+
in mass surveillance programs;
|
| 244 |
+
|
| 245 |
+
* 3.1.18. Military Activities: Be an entity or a representative, agent,
|
| 246 |
+
affiliate, successor, attorney, or assign of an entity which conducts
|
| 247 |
+
military activities;
|
| 248 |
+
|
| 249 |
+
* 3.1.19. Law Enforcement: Be an individual or entity, or a representative,
|
| 250 |
+
agent, affiliate, successor, attorney, or assign of an individual or
|
| 251 |
+
entity, that provides good or services to, or otherwise enters into any
|
| 252 |
+
commercial contracts with, any local, state, or federal law enforcement
|
| 253 |
+
agency;
|
| 254 |
+
|
| 255 |
+
* 3.1.20. Media: Be an individual or entity, or a representative, agent,
|
| 256 |
+
affiliate, successor, attorney, or assign of an individual or entity, that
|
| 257 |
+
broadcasts messages promoting killing, torture, or other forms of extreme
|
| 258 |
+
violence;
|
| 259 |
+
|
| 260 |
+
* 3.1.21. Interfere with Workers’ free exercise of the right to organize and
|
| 261 |
+
associate (See Article 20, United Nations Universal Declaration of Human
|
| 262 |
+
Rights; C087 - Freedom of Association and Protection of the Right to
|
| 263 |
+
Organise Convention, 1948 (No. 87), International Labour Organization;
|
| 264 |
+
Article 8, International Covenant on Economic, Social and Cultural Rights);
|
| 265 |
+
and
|
| 266 |
+
|
| 267 |
+
* 3.1.22. Harm the environment in a manner inconsistent with local, state,
|
| 268 |
+
national, or international law.
|
| 269 |
+
|
| 270 |
+
* 3.2. The Licensee SHALL:
|
| 271 |
+
|
| 272 |
+
* 3.2.1. Social Auditing: Only use social auditing mechanisms that adhere to
|
| 273 |
+
Worker-Driven Social Responsibility Network’s Statement of Principles
|
| 274 |
+
(https://wsr-network.org/what-is-wsr/statement-of-principles/
|
| 275 |
+
[https://wsr-network.org/what-is-wsr/statement-of-principles/]) over
|
| 276 |
+
traditional social auditing mechanisms, to the extent the Licensee uses
|
| 277 |
+
any social auditing mechanisms at all;
|
| 278 |
+
|
| 279 |
+
* 3.2.2. Supply Chain: Provide clear, accessible supply chain data to the
|
| 280 |
+
public in accordance with the following conditions:
|
| 281 |
+
|
| 282 |
+
* 3.2.2.1. All data will be on Licensee’s website and/or, to the extent
|
| 283 |
+
Licensee is a representative, agent, affiliate, successor, attorney,
|
| 284 |
+
subsidiary, or assign, on Licensee’s principal’s or parent’s website or
|
| 285 |
+
some other online platform accessible to the public via an internet
|
| 286 |
+
search on a common internet search engine; and
|
| 287 |
+
|
| 288 |
+
* 3.2.2.2. Data published will include, where applicable, manufacturers,
|
| 289 |
+
top tier suppliers, subcontractors, cooperatives, component parts
|
| 290 |
+
producers, and farms;
|
| 291 |
+
|
| 292 |
+
* 3.2.3. Provide equal pay for equal work where the performance of such work
|
| 293 |
+
requires equal skill, effort, and responsibility, and which are performed
|
| 294 |
+
under similar working conditions, except where such payment is made
|
| 295 |
+
pursuant to:
|
| 296 |
+
|
| 297 |
+
* 3.2.3.1. A seniority system;
|
| 298 |
+
|
| 299 |
+
* 3.2.3.2. A merit system;
|
| 300 |
+
|
| 301 |
+
* 3.2.3.3. A system which measures earnings by quantity or quality of
|
| 302 |
+
production; or
|
| 303 |
+
|
| 304 |
+
* 3.2.3.4. A differential based on any other factor other than sex, gender,
|
| 305 |
+
sexual orientation, race, ethnicity, nationality, religion, caste, age,
|
| 306 |
+
medical disability or impairment, and/or any other like circumstances
|
| 307 |
+
(See 29 U.S.C.A. § 206(d)(1); Article 23, United Nations Universal
|
| 308 |
+
Declaration of Human Rights; Article 7, International Covenant on
|
| 309 |
+
Economic, Social and Cultural Rights; Article 26, International Covenant
|
| 310 |
+
on Civil and Political Rights); and
|
| 311 |
+
|
| 312 |
+
* 3.2.4. Allow for reasonable limitation of working hours and periodic
|
| 313 |
+
holidays with pay (See Article 24, United Nations Universal Declaration of
|
| 314 |
+
Human Rights; Article 7, International Covenant on Economic, Social and
|
| 315 |
+
Cultural Rights).
|
| 316 |
+
|
| 317 |
+
4. SUPPLY CHAIN IMPACTED PARTIES:
|
| 318 |
+
|
| 319 |
+
This section identifies additional individuals or entities that a Licensee could
|
| 320 |
+
harm as a result of violating the Ethical Standards section, the condition that
|
| 321 |
+
the Licensee must voluntarily accept a Duty of Care for those individuals or
|
| 322 |
+
entities, and the right to a private right of action that those individuals or
|
| 323 |
+
entities possess as a result of violations of the Ethical Standards section.
|
| 324 |
+
|
| 325 |
+
4.1. In addition to the above Ethical Standards, Licensee voluntarily accepts a
|
| 326 |
+
Duty of Care for Supply Chain Impacted Parties of this License, including
|
| 327 |
+
individuals and communities impacted by violations of the Ethical Standards. The
|
| 328 |
+
Duty of Care is breached when a provision within the Ethical Standards section
|
| 329 |
+
is violated by a Licensee, one of its successors or assigns, or by an individual
|
| 330 |
+
or entity that exists within the Supply Chain prior to a good or service
|
| 331 |
+
reaching the Licensee.
|
| 332 |
+
|
| 333 |
+
4.2. Breaches of the Duty of Care, as stated within this section, shall create a
|
| 334 |
+
private right of action, allowing any Supply Chain Impacted Party harmed by the
|
| 335 |
+
Licensee to take legal action against the Licensee in accordance with applicable
|
| 336 |
+
negligence laws, whether they be in tort law, delict law, and/or similar bodies
|
| 337 |
+
of law closely related to tort and/or delict law, regardless if Licensee is
|
| 338 |
+
directly responsible for the harms suffered by a Supply Chain Impacted Party.
|
| 339 |
+
Nothing in this section shall be interpreted to include acts committed by
|
| 340 |
+
individuals outside of the scope of his/her/their employment.
|
| 341 |
+
|
| 342 |
+
5. NOTICE: This section explains when a Licensee must notify others of the
|
| 343 |
+
License.
|
| 344 |
+
|
| 345 |
+
5.1. Distribution of Notice: Licensee must ensure that everyone who receives a
|
| 346 |
+
copy of or uses any part of Software from Licensee, with or without changes,
|
| 347 |
+
also receives the License and the copyright notice included with Software (and
|
| 348 |
+
if included by the Licensor, patent, trademark, and attribution notice).
|
| 349 |
+
Licensee must ensure that License is prominently displayed so that any
|
| 350 |
+
individual or entity seeking to download, copy, use, or otherwise receive any
|
| 351 |
+
part of Software from Licensee is notified of this License and its terms and
|
| 352 |
+
conditions. Licensee must cause any modified versions of the Software to carry
|
| 353 |
+
prominent notices stating that Licensee changed the Software.
|
| 354 |
+
|
| 355 |
+
5.2. Modified Software: Licensee is free to create modifications of the Software
|
| 356 |
+
and distribute only the modified portion created by Licensee, however, any
|
| 357 |
+
derivative work stemming from the Software or its code must be distributed
|
| 358 |
+
pursuant to this License, including this Notice provision.
|
| 359 |
+
|
| 360 |
+
5.3. Recipients as Licensees: Any individual or entity that uses, copies,
|
| 361 |
+
modifies, reproduces, distributes, or prepares derivative work based upon the
|
| 362 |
+
Software, all or part of the Software’s code, or a derivative work developed by
|
| 363 |
+
using the Software, including a portion of its code, is a Licensee as defined
|
| 364 |
+
above and is subject to the terms and conditions of this License.
|
| 365 |
+
|
| 366 |
+
6. REPRESENTATIONS AND WARRANTIES:
|
| 367 |
+
|
| 368 |
+
6.1. Disclaimer of Warranty: TO THE FULL EXTENT ALLOWED BY LAW, THIS SOFTWARE
|
| 369 |
+
COMES “AS IS,” WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED, AND LICENSOR SHALL NOT
|
| 370 |
+
BE LIABLE TO ANY PERSON OR ENTITY FOR ANY DAMAGES OR OTHER LIABILITY ARISING
|
| 371 |
+
FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THIS LICENSE, UNDER ANY
|
| 372 |
+
LEGAL CLAIM.
|
| 373 |
+
|
| 374 |
+
6.2. Limitation of Liability: LICENSEE SHALL HOLD LICENSOR HARMLESS AGAINST ANY
|
| 375 |
+
AND ALL CLAIMS, DEBTS, DUES, LIABILITIES, LIENS, CAUSES OF ACTION, DEMANDS,
|
| 376 |
+
OBLIGATIONS, DISPUTES, DAMAGES, LOSSES, EXPENSES, ATTORNEYS’ FEES, COSTS,
|
| 377 |
+
LIABILITIES, AND ALL OTHER CLAIMS OF EVERY KIND AND NATURE WHATSOEVER, WHETHER
|
| 378 |
+
KNOWN OR UNKNOWN, ANTICIPATED OR UNANTICIPATED, FORESEEN OR UNFORESEEN, ACCRUED
|
| 379 |
+
OR UNACCRUED, DISCLOSED OR UNDISCLOSED, ARISING OUT OF OR RELATING TO LICENSEE’S
|
| 380 |
+
USE OF THE SOFTWARE. NOTHING IN THIS SECTION SHOULD BE INTERPRETED TO REQUIRE
|
| 381 |
+
LICENSEE TO INDEMNIFY LICENSOR, NOR REQUIRE LICENSOR TO INDEMNIFY LICENSEE.
|
| 382 |
+
|
| 383 |
+
7. TERMINATION
|
| 384 |
+
|
| 385 |
+
7.1. Violations of Ethical Standards or Breaching Duty of Care: If Licensee
|
| 386 |
+
violates the Ethical Standards section or Licensee, or any other person or
|
| 387 |
+
entity within the Supply Chain prior to a good or service reaching the Licensee,
|
| 388 |
+
breaches its Duty of Care to Supply Chain Impacted Parties, Licensee must remedy
|
| 389 |
+
the violation or harm caused by Licensee within 30 days of being notified of the
|
| 390 |
+
violation or harm. If Licensee fails to remedy the violation or harm within 30
|
| 391 |
+
days, all rights in the Software granted to Licensee by License will be null and
|
| 392 |
+
void as between Licensor and Licensee.
|
| 393 |
+
|
| 394 |
+
7.2. Failure of Notice: If any person or entity notifies Licensee in writing
|
| 395 |
+
that Licensee has not complied with the Notice section of this License, Licensee
|
| 396 |
+
can keep this License by taking all practical steps to comply within 30 days
|
| 397 |
+
after the notice of noncompliance. If Licensee does not do so, Licensee’s
|
| 398 |
+
License (and all rights licensed hereunder) will end immediately.
|
| 399 |
+
|
| 400 |
+
7.3. Judicial Findings: In the event Licensee is found by a civil, criminal,
|
| 401 |
+
administrative, or other court of competent jurisdiction, or some other
|
| 402 |
+
adjudicating body with legal authority, to have committed actions which are in
|
| 403 |
+
violation of the Ethical Standards or Supply Chain Impacted Party sections of
|
| 404 |
+
this License, all rights granted to Licensee by this License will terminate
|
| 405 |
+
immediately.
|
| 406 |
+
|
| 407 |
+
7.4. Patent Litigation: If Licensee institutes patent litigation against any
|
| 408 |
+
entity (including a cross-claim or counterclaim in a suit) alleging that the
|
| 409 |
+
Software, all or part of the Software’s code, or a derivative work developed
|
| 410 |
+
using the Software, including a portion of its code, constitutes direct or
|
| 411 |
+
contributory patent infringement, then any patent license, along with all other
|
| 412 |
+
rights, granted to Licensee under this License will terminate as of the date
|
| 413 |
+
such litigation is filed.
|
| 414 |
+
|
| 415 |
+
7.5. Additional Remedies: Termination of the License by failing to remedy harms
|
| 416 |
+
in no way prevents Licensor or Supply Chain Impacted Party from seeking
|
| 417 |
+
appropriate remedies at law or in equity.
|
| 418 |
+
|
| 419 |
+
8. MISCELLANEOUS:
|
| 420 |
+
|
| 421 |
+
8.1. Conditions: Sections 3, 4.1, 5.1, 5.2, 7.1, 7.2, 7.3, and 7.4 are
|
| 422 |
+
conditions of the rights granted to Licensee in the License.
|
| 423 |
+
|
| 424 |
+
8.2. Equitable Relief: Licensor and any Supply Chain Impacted Party shall be
|
| 425 |
+
entitled to equitable relief, including injunctive relief or specific
|
| 426 |
+
performance of the terms hereof, in addition to any other remedy to which they
|
| 427 |
+
are entitled at law or in equity.
|
| 428 |
+
|
| 429 |
+
8.3. Copyleft: Modified software, source code, or other derivative work must be
|
| 430 |
+
licensed, in its entirety, under the exact same conditions as this License.
|
| 431 |
+
|
| 432 |
+
8.4. Severability: If any term or provision of this License is determined to be
|
| 433 |
+
invalid, illegal, or unenforceable by a court of competent jurisdiction, any
|
| 434 |
+
such determination of invalidity, illegality, or unenforceability shall not
|
| 435 |
+
affect any other term or provision of this License or invalidate or render
|
| 436 |
+
unenforceable such term or provision in any other jurisdiction. If the
|
| 437 |
+
determination of invalidity, illegality, or unenforceability by a court of
|
| 438 |
+
competent jurisdiction pertains to the terms or provisions contained in the
|
| 439 |
+
Ethical Standards section of this License, all rights in the Software granted to
|
| 440 |
+
Licensee shall be deemed null and void as between Licensor and Licensee.
|
| 441 |
+
|
| 442 |
+
8.5. Section Titles: Section titles are solely written for organizational
|
| 443 |
+
purposes and should not be used to interpret the language within each section.
|
| 444 |
+
|
| 445 |
+
8.6. Citations: Citations are solely written to provide context for the source
|
| 446 |
+
of the provisions in the Ethical Standards.
|
| 447 |
+
|
| 448 |
+
8.7. Section Summaries: Some sections have a brief italicized description which
|
| 449 |
+
is provided for the sole purpose of briefly describing the section and should
|
| 450 |
+
not be used to interpret the terms of the License.
|
| 451 |
+
|
| 452 |
+
8.8. Entire License: This is the entire License between the Licensor and
|
| 453 |
+
Licensee with respect to the claims released herein and that the consideration
|
| 454 |
+
stated herein is the only consideration or compensation to be paid or exchanged
|
| 455 |
+
between them for this License. This License cannot be modified or amended except
|
| 456 |
+
in a writing signed by Licensor and Licensee.
|
| 457 |
+
|
| 458 |
+
8.9. Successors and Assigns: This License shall be binding upon and inure to the
|
| 459 |
+
benefit of the Licensor’s and Licensee’s respective heirs, successors, and
|
| 460 |
+
assigns.
|
| 461 |
+
---------------------- END OFFICIAL HIPPOCRATIC LICENSE 3.0 TEXT ----------------------
|
| 462 |
+
|
| 463 |
+
==============================================================================
|
| 464 |
+
Attribution, commercial use, and warranty
|
| 465 |
+
==============================================================================
|
| 466 |
+
|
| 467 |
+
Attribution: cite this work as described in the model card (README.md), section
|
| 468 |
+
"How to cite". Attribution to Lowdown Labs is required under CC BY-NC 4.0.
|
| 469 |
+
|
| 470 |
+
Commercial use: CC BY-NC 4.0 does not grant commercial rights. Commercial licenses are
|
| 471 |
+
sold by Lowdown Labs; contact Lowdown Labs to purchase one.
|
| 472 |
+
|
| 473 |
+
No warranty: this work is provided as is, without warranty of any kind. See the model card
|
| 474 |
+
for the intended use, the evaluated conditions, and the known limitations.
|
README.md
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: other
|
| 3 |
+
license_name: lowdown-labs-lovely-license-1.0
|
| 4 |
+
license_link: LICENSE
|
| 5 |
+
tags:
|
| 6 |
+
- fela
|
| 7 |
+
- fourier-neural-operator
|
| 8 |
+
- fno
|
| 9 |
+
- gated-deltanet
|
| 10 |
+
- cpu
|
| 11 |
+
- on-device
|
| 12 |
+
- code
|
| 13 |
+
- autocomplete
|
| 14 |
+
- fill-in-the-middle
|
| 15 |
+
- constant-memory
|
| 16 |
+
library_name: transformers
|
| 17 |
+
pipeline_tag: text-generation
|
| 18 |
+
language:
|
| 19 |
+
- code
|
| 20 |
+
model-index:
|
| 21 |
+
- name: fela-autocomplete
|
| 22 |
+
results:
|
| 23 |
+
- task:
|
| 24 |
+
type: text-generation
|
| 25 |
+
name: Fill in the middle single line infilling
|
| 26 |
+
dataset:
|
| 27 |
+
type: humaneval-singlelineinfilling
|
| 28 |
+
name: HumanEval SingleLineInfilling
|
| 29 |
+
metrics:
|
| 30 |
+
- type: pass@1
|
| 31 |
+
value: 54.6
|
| 32 |
+
name: FIM pass@1
|
| 33 |
+
---
|
| 34 |
+
|
| 35 |
+
# FELA LLM 1.5: On device code autocomplete (fill in the middle)
|
| 36 |
+
|
| 37 |
+
FELA Autocomplete is a code completion model. You give it the code before your cursor, and
|
| 38 |
+
optionally more codebase context, and it writes the piece that goes in between. This is
|
| 39 |
+
the same fill in the middle idea that powers the gray autocomplete text in a modern editor.
|
| 40 |
+
It is a 1.79 billion parameter model that runs on a plain CPU with no GPU, so it can sit
|
| 41 |
+
inside a local IDE helper or an on premises code tool and complete code without sending your
|
| 42 |
+
source to the cloud.
|
| 43 |
+
|
| 44 |
+
It was warm started from Qwen2.5-Coder 1.5B and clean room distilled, then annealed and
|
| 45 |
+
supervised fine tuned for fill in the middle. Our key niche insight is to provide for inline single line
|
| 46 |
+
completion, not full text generation. We feel this a great compromise to have a speedy
|
| 47 |
+
development experience while still having a product that doesn't contribute to cognitive
|
| 48 |
+
atrophy and feels better to use.
|
| 49 |
+
|
| 50 |
+
# Headline result: fill in the middle
|
| 51 |
+
|
| 52 |
+
We wanted to apply the FELA methodology as an LLM. Given a tight training budget while we
|
| 53 |
+
study how to scale this new architecture, we thought a smaller model would be a great
|
| 54 |
+
autocomplete tool to demonstrate the power of efficient computing.
|
| 55 |
+
|
| 56 |
+
We measure functional pass@1 with the HumanEval-SingleLineInfilling methodology, so
|
| 57 |
+
a completion counts only when it makes the code run correctly, not when it matches the
|
| 58 |
+
original character for character.
|
| 59 |
+
|
| 60 |
+
| Stage | FIM Pass@1 | FIM EM | FIM Edit Sim | MBPP | HumanEval |
|
| 61 |
+
|---|---|---|---|---|---|
|
| 62 |
+
| Base (15B token distill) | 49.6% | 42.0 | 73.6 | 13.0 | 11.0 |
|
| 63 |
+
| Plus fill in the middle anneal | 54.4% | 47.4 | 77.6 | 16.0 | 9.8 |
|
| 64 |
+
| Plus fill in the middle SFT (final) | **54.6%** | 46.8 | **78.4** | **18.0** | 11.0 |
|
| 65 |
+
|
| 66 |
+
Over half of single line completions functionally work. We lead with FIM pass@1 because that
|
| 67 |
+
is the product metric. The Rust server auto formats the output in microseconds, so we optimize
|
| 68 |
+
for semantic correctness (pass@1 and edit similarity), not whitespace exact match.
|
| 69 |
+
|
| 70 |
+
MBPP and HumanEval are shown for context only. They ask the model to write a whole function
|
| 71 |
+
from a description, which is the wrong lens for an autocomplete model and low by design at this
|
| 72 |
+
size. We provide it to compare with other language models at size ~1.5B. Do not read the HumanEval number as the quality of the product; read the FIM pass@1.
|
| 73 |
+
|
| 74 |
+
# How it got here
|
| 75 |
+
|
| 76 |
+
1. Base: clean room distill from Qwen2.5-Coder 1.5B to 15 billion tokens, on a permissive code
|
| 77 |
+
mix with fill in the middle in the objective.
|
| 78 |
+
2. Fill in the middle anneal (the big lever): a further billion tokens with a line aware fill
|
| 79 |
+
in the middle objective (mask whole lines, matching how the eval scores lines) across
|
| 80 |
+
Python, JavaScript, TypeScript, Java, Go, Rust, and C plus plus. This train and eval
|
| 81 |
+
alignment gave the largest jump.
|
| 82 |
+
3. Fill in the middle SFT: a further 1.2 billion tokens with the native Qwen fill in the middle
|
| 83 |
+
tokens and the loss on the middle span. This consolidated the gains and lifted general code
|
| 84 |
+
(MBPP 16 to 18).
|
| 85 |
+
|
| 86 |
+
# What goes in, what comes out
|
| 87 |
+
|
| 88 |
+
- Input: your code as text, split into a prefix (before the cursor) and an optional suffix
|
| 89 |
+
(after the cursor). The text is turned into tokens with the Qwen2.5-Coder tokenizer, which
|
| 90 |
+
carries the fill in the middle markers `<|fim_prefix|>`, `<|fim_suffix|>`, and
|
| 91 |
+
`<|fim_middle|>`.
|
| 92 |
+
- Output: the code that belongs between the prefix and the suffix. By default it writes one
|
| 93 |
+
line and stops, which is what an inline autocomplete wants. With no suffix it simply
|
| 94 |
+
continues the prefix.
|
| 95 |
+
- In plain terms: you type `import numpy as ` and it finishes the line with ` np`; you give it
|
| 96 |
+
the body of `def add(a, b):` with the call `add(2, 3)` waiting below it, and it fills in
|
| 97 |
+
` return a + b`.
|
| 98 |
+
|
| 99 |
+
# Why we built it this way
|
| 100 |
+
|
| 101 |
+
The model has no growing cache of past tokens, which is the usual reason memory creeps up as
|
| 102 |
+
context gets longer. Its sequence mixers are Fourier Neural Operators (a filter the model
|
| 103 |
+
learns and applies in the frequency domain) for global context, Gated-DeltaNet recall layers
|
| 104 |
+
that overwrite an old memory when a new one arrives (so keys do not interfere), and a Landmark
|
| 105 |
+
routing layer that lets a token look back at summaries of earlier chunks. None of these keep a
|
| 106 |
+
per token attention cache, so the working memory stays small and fixed no matter how much code
|
| 107 |
+
is in the window. That is what lets it decode on a low power CPU next to you, with the source
|
| 108 |
+
never leaving the machine.
|
| 109 |
+
|
| 110 |
+
The full stack is 28 layers at width 1536, in the repeating pattern of three Fourier mixers
|
| 111 |
+
then one Gated-DeltaNet recall layer, with a Landmark routing layer every seventh layer.
|
| 112 |
+
|
| 113 |
+
# Performance
|
| 114 |
+
|
| 115 |
+
The model runs on CPU with no GPU. Two paths run these weights:
|
| 116 |
+
|
| 117 |
+
| Path | Format | Size on disk | Single core decode |
|
| 118 |
+
|---|---|---|---|
|
| 119 |
+
| Reference (this repo, `modeling.py`) | bf16 | 3.58 GB | about 4 tokens per second |
|
| 120 |
+
| Production (FELA server, separate Rust runtime) | int8 | about 2.08 GB | about 22 tokens per second |
|
| 121 |
+
|
| 122 |
+
The `modeling.py` loader here is the plain, readable reference path in pure PyTorch. It loads
|
| 123 |
+
the weights, runs a real forward, and decodes on CPU, which is enough for the quickstart and for
|
| 124 |
+
verifying the model. It is a correctness path, not the fast path, so do not read its speed as the
|
| 125 |
+
product speed. Loading `model_int8.safetensors` in Python is smaller in memory but not faster,
|
| 126 |
+
because the pure torch int8 path dequantizes the weights on the fly.
|
| 127 |
+
|
| 128 |
+
The fast path is the CPU native FELA server, a separate Rust runtime that runs these weights as
|
| 129 |
+
int8 with a constant state streaming decode and no KV cache. On one core it decodes at about 22
|
| 130 |
+
tokens per second, roughly 20 times the plain f32 path, measured at this model's shape with a
|
| 131 |
+
steady state O(1) decode step. Single stream decode is bound by memory bandwidth, since it
|
| 132 |
+
streams the full int8 weight set once per token, so adding cores does not speed up one stream
|
| 133 |
+
(measured flat from one to eight cores); extra cores serve more streams at once and speed up the
|
| 134 |
+
prefill. The server's Rust int8 forward is checked against the PyTorch model with a golden test,
|
| 135 |
+
so the fast serving path produces the same model, not a lookalike.
|
| 136 |
+
|
| 137 |
+
# What to expect
|
| 138 |
+
|
| 139 |
+
Some real completions from the final model:
|
| 140 |
+
|
| 141 |
+
- `import numpy as ` gives ` np`
|
| 142 |
+
- prefix `def add(a, b):` with the call `add(2, 3)` in the suffix gives ` return a + b`
|
| 143 |
+
- prefix `def is_even(n):\n return n % 2 == ` gives `0`
|
| 144 |
+
|
| 145 |
+
Where it earns its keep is single line fill in the middle on the patterns developers write all
|
| 146 |
+
day - and it can be made more useful with prefilled repository context.
|
| 147 |
+
It is a 1.5B class model, so it is not a whole function generator or a reasoning model:
|
| 148 |
+
multi line blocks, novel algorithms, and anything that needs deep reasoning about your specific
|
| 149 |
+
code are outside what it is built for. Read completions before you use them.
|
| 150 |
+
|
| 151 |
+
# How to run it
|
| 152 |
+
|
| 153 |
+
It runs on CPU; no GPU is required. See `quickstart/` for a runnable example. The short
|
| 154 |
+
version, using the self contained `modeling.py`, `model_cpu_gpt2.py`, and `config.json` in
|
| 155 |
+
this repo:
|
| 156 |
+
|
| 157 |
+
```python
|
| 158 |
+
from modeling import load_model
|
| 159 |
+
m = load_model("/path/to/this/repo")
|
| 160 |
+
|
| 161 |
+
# Fill in the middle: code before and after the cursor -> the middle
|
| 162 |
+
r = m.complete("def add(a, b):\n ", suffix="\nresult = add(2, 3)\n")
|
| 163 |
+
print(r["middle"]) # e.g. " return a + b"
|
| 164 |
+
|
| 165 |
+
# Plain autocomplete: continue a single line
|
| 166 |
+
print(m.complete("import numpy as ")["middle"]) # e.g. " np"
|
| 167 |
+
|
| 168 |
+
# Load the smaller int8 weights instead (same completions, smaller on disk)
|
| 169 |
+
m8 = load_model("/path/to/this/repo", quant="int8")
|
| 170 |
+
```
|
| 171 |
+
|
| 172 |
+
It also loads with transformers directly. The code is custom, so pass `trust_remote_code=True`:
|
| 173 |
+
|
| 174 |
+
```python
|
| 175 |
+
import torch
|
| 176 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 177 |
+
|
| 178 |
+
model = AutoModelForCausalLM.from_pretrained("lowdown-labs/fela-autocomplete", trust_remote_code=True, dtype=torch.bfloat16)
|
| 179 |
+
tok = AutoTokenizer.from_pretrained("lowdown-labs/fela-autocomplete", trust_remote_code=True)
|
| 180 |
+
prompt = "<|fim_prefix|>def add(a, b):\n <|fim_suffix|>\nresult = add(2, 3)\n<|fim_middle|>"
|
| 181 |
+
enc = tok(prompt, return_tensors="pt")
|
| 182 |
+
out = model.generate(**enc, max_new_tokens=8, use_cache=False)
|
| 183 |
+
print(tok.decode(out[0, enc["input_ids"].shape[1]:], skip_special_tokens=True))
|
| 184 |
+
```
|
| 185 |
+
|
| 186 |
+
The loader reads the bf16 `model.safetensors` by default. Pass `quant="int8"` to load the
|
| 187 |
+
smaller `model_int8.safetensors` instead; it dequantizes the linear weights with their per
|
| 188 |
+
channel scales and keeps the Fourier filters in bf16, giving the same completions. Pass
|
| 189 |
+
`quant="auto"` to prefer bf16 when present and fall back to int8.
|
| 190 |
+
|
| 191 |
+
`complete` is greedy by default, so a skeptic gets the same real output twice. For an
|
| 192 |
+
interactive playground, see the Hugging Face Space in `space/`. For production serving, use
|
| 193 |
+
the CPU native FELA server (`https://github.com/Lowdown-Labs/fela_server`).
|
| 194 |
+
|
| 195 |
+
## Loading, exports, and verification
|
| 196 |
+
|
| 197 |
+
- Weights ship as `model.safetensors` in bf16 (no pickle code execution risk). `config.json`
|
| 198 |
+
holds the architecture hyperparameters. `tokenizer.json` is the Qwen2.5-Coder tokenizer with
|
| 199 |
+
the fill in the middle tokens. The architecture is defined in the self contained
|
| 200 |
+
`model_cpu_gpt2.py`, and the pure torch CPU paths for the Gated-DeltaNet and Landmark layers
|
| 201 |
+
are in `cpu_delta.py`, `cpu_landmark.py`, `cpu_swa.py`, and `cpu_patch.py`, which ship beside
|
| 202 |
+
it. `modeling.py` wires them into a loader with a `complete` fill in the middle entry point.
|
| 203 |
+
- `verify.py` builds the model, loads the weights, runs a fixed input forward, checks the
|
| 204 |
+
output shape and the vocabulary size, confirms the logits are finite, and compares the top
|
| 205 |
+
predicted tokens against a captured reference.
|
| 206 |
+
|
| 207 |
+
## Formats
|
| 208 |
+
|
| 209 |
+
- bf16: the reference weights and the default load path in this repo (`model.safetensors`,
|
| 210 |
+
3.58 GB).
|
| 211 |
+
- int8: the smaller on device format (`model_int8.safetensors`, about 2.08 GB), weight only int8
|
| 212 |
+
per channel on the large linear layers, with the Fourier filters kept in bf16. Load it in
|
| 213 |
+
Python with `load_model(dir, quant="int8")`, or serve it with the FELA server. The int8
|
| 214 |
+
forward matches the bf16 model by the golden test.
|
| 215 |
+
|
| 216 |
+
## Model details
|
| 217 |
+
|
| 218 |
+
- Parameters: 1,788,379,536 (about 1.79 billion).
|
| 219 |
+
- Layers: 28, width 1536, 12 heads, feed forward hidden 8960.
|
| 220 |
+
- Sequence mixers: Fourier Neural Operator (512 modes), Gated-DeltaNet recall, and Landmark
|
| 221 |
+
global routing, in the SSSL pattern (three Fourier mixers then one recall layer), with a
|
| 222 |
+
Landmark layer every seventh layer.
|
| 223 |
+
- Tokenizer: Qwen2.5-Coder (vocabulary 151936), which carries the fill in the middle tokens.
|
| 224 |
+
- Warm start: Qwen2.5-Coder 1.5B, then clean room distilled, annealed, and fill in the middle
|
| 225 |
+
supervised fine tuned.
|
| 226 |
+
|
| 227 |
+
# Intended use, limitations, and safety
|
| 228 |
+
|
| 229 |
+
What it is for: inline code autocomplete and fill in the middle inside a local or on premises
|
| 230 |
+
developer tool, where running on CPU with no GPU and keeping the source on the machine matter.
|
| 231 |
+
It is a research preview for that use.
|
| 232 |
+
|
| 233 |
+
What it is not for: it is not a whole function generator, not a chat model, and not a reasoning
|
| 234 |
+
model. Do not rely on its completions for correctness or security without reading them, and do
|
| 235 |
+
not ship it into a product without your own evaluation. It is a 1.5B class model and will be
|
| 236 |
+
wrong on anything past common single line patterns.
|
| 237 |
+
|
| 238 |
+
Evaluated conditions and known failure modes:
|
| 239 |
+
|
| 240 |
+
- Strong on single line, high frequency fill in the middle; weaker on multi line blocks and
|
| 241 |
+
novel logic.
|
| 242 |
+
- The reference `modeling.py` path is bf16 and slow; the int8 FELA server is the fast path.
|
| 243 |
+
- No safety or license filtering of generated code is claimed. Review generated code before you
|
| 244 |
+
use it.
|
| 245 |
+
|
| 246 |
+
Privacy: the model runs on the device or on your own CPU, so your source does not have to leave
|
| 247 |
+
the machine and there is no per call API. That is the on device privacy angle.
|
| 248 |
+
|
| 249 |
+
# Model family
|
| 250 |
+
|
| 251 |
+
This is part of the FELA family from Lowdown Labs: one Fourier Neural Operator architecture
|
| 252 |
+
across many modalities, all CPU native and subquadratic. This repo is pushed as
|
| 253 |
+
`lowdown-labs/FELA-autocomplete`. Sibling repos are trained independently per modality and
|
| 254 |
+
share no weights, so none carries a `base_model` link.
|
| 255 |
+
|
| 256 |
+
# Acknowledgements and references
|
| 257 |
+
|
| 258 |
+
- Fourier Neural Operator: Li, Z., et al. (2021). Fourier Neural Operator for Parametric
|
| 259 |
+
Partial Differential Equations. ICLR. https://arxiv.org/abs/2010.08895
|
| 260 |
+
- Gated Linear Attention: Yang, S., et al. (2023). Gated Linear Attention Transformers with
|
| 261 |
+
Hardware-Efficient Training. https://arxiv.org/abs/2312.06635
|
| 262 |
+
- Gated DeltaNet: Yang, S., et al. (2024). Gated Delta Networks: Improving Mamba2 with Delta
|
| 263 |
+
Rule. https://arxiv.org/abs/2412.06464
|
| 264 |
+
- Landmark Attention: Mohtashami, A., Jaggi, M. (2023). Landmark Attention: Random-Access
|
| 265 |
+
Infinite Context Length for Transformers. https://arxiv.org/abs/2305.16300
|
| 266 |
+
- Qwen2.5-Coder: Hui, B., et al. (2024). Qwen2.5-Coder Technical Report.
|
| 267 |
+
https://arxiv.org/abs/2409.12186
|
| 268 |
+
- PyTorch: Paszke, A., et al. (2019). NeurIPS. https://arxiv.org/abs/1912.01703
|
| 269 |
+
- flash-linear-attention: the reference kernels for the Gated-DeltaNet layer.
|
| 270 |
+
https://github.com/fla-org/flash-linear-attention
|
| 271 |
+
|
| 272 |
+
# How to cite
|
| 273 |
+
|
| 274 |
+
```bibtex
|
| 275 |
+
@misc{lowdownlabs_fela_llm,
|
| 276 |
+
title = {FELA LLM 1.5: An on device Fourier Neural Operator code autocomplete model},
|
| 277 |
+
author = {Lowdown Labs},
|
| 278 |
+
year = {2026},
|
| 279 |
+
note = {Model card}
|
| 280 |
+
}
|
| 281 |
+
```
|
| 282 |
+
|
| 283 |
+
# License
|
| 284 |
+
|
| 285 |
+
Released under the Lowdown Labs Lovely License 1.0 (CC BY-NC 4.0 plus Hippocratic License 3.0). See LICENSE. For most LL models, a commercial license may be available; contact Lowdown Labs.
|
config.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"model_type": "fela",
|
| 3 |
+
"library_name": "pytorch",
|
| 4 |
+
"arch": "CPUGPT (FELA LM)",
|
| 5 |
+
"edition": "FELA LLM 1.5 (code, 1.5B class)",
|
| 6 |
+
"note": "FELA code language model for fill in the middle autocomplete. 1.79B parameters. 28 layers of FNO spectral token mixers plus Gated-DeltaNet recall plus Landmark global routing (SSSL pattern). Final fill in the middle SFT model.",
|
| 7 |
+
"quant": "bf16",
|
| 8 |
+
"vocab_size": 151936,
|
| 9 |
+
"n_layer": 28,
|
| 10 |
+
"n_embd": 1536,
|
| 11 |
+
"n_head": 12,
|
| 12 |
+
"ffn_hidden": 8960,
|
| 13 |
+
"fno_modes": 512,
|
| 14 |
+
"gla_chunk": 256,
|
| 15 |
+
"layer_pattern": "SSSL",
|
| 16 |
+
"gla_delta": true,
|
| 17 |
+
"landmark_layer_every": 7,
|
| 18 |
+
"landmark_chunk": 32,
|
| 19 |
+
"landmark_max": 64,
|
| 20 |
+
"attn_layer_every": 0,
|
| 21 |
+
"seq_len": 2048,
|
| 22 |
+
"n_params": 1788379536,
|
| 23 |
+
"tokenizer": "Qwen2.5-Coder (tokenizer.json, vocab 151936, carries the FIM tokens <|fim_prefix|> / <|fim_suffix|> / <|fim_middle|>)",
|
| 24 |
+
"fim_tokens": {
|
| 25 |
+
"prefix": "<|fim_prefix|>",
|
| 26 |
+
"suffix": "<|fim_suffix|>",
|
| 27 |
+
"middle": "<|fim_middle|>"
|
| 28 |
+
},
|
| 29 |
+
"input_desc": "token ids from the Qwen2.5-Coder tokenizer. For fill in the middle: <|fim_prefix|> P <|fim_suffix|> S <|fim_middle|>, and the model completes the middle. For plain continuation: the prompt token ids.",
|
| 30 |
+
"serving": "Runs on a plain CPU with no GPU via the FELA server (int8, constant memory streaming decode, no KV cache). The bf16 model.safetensors is the reference; model_int8.safetensors is the int8 serving export.",
|
| 31 |
+
"int8_variant": "model_int8.safetensors",
|
| 32 |
+
"int8_scheme": "weight only int8 per channel symmetric on linear layers; scales fp32; kept tensors bf16; keys prefixed int8 / scale / keep",
|
| 33 |
+
"architectures": [
|
| 34 |
+
"FelaForCausalLM"
|
| 35 |
+
],
|
| 36 |
+
"auto_map": {
|
| 37 |
+
"AutoConfig": "configuration_fela.FelaConfig",
|
| 38 |
+
"AutoModelForCausalLM": "modeling_fela.FelaForCausalLM"
|
| 39 |
+
}
|
| 40 |
+
}
|
configuration_fela.py
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from transformers import PretrainedConfig
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
class FelaConfig(PretrainedConfig):
|
| 5 |
+
model_type = "fela"
|
| 6 |
+
|
| 7 |
+
def __init__(
|
| 8 |
+
self,
|
| 9 |
+
vocab_size=151936,
|
| 10 |
+
seq_len=2048,
|
| 11 |
+
n_layer=28,
|
| 12 |
+
n_embd=1536,
|
| 13 |
+
n_head=12,
|
| 14 |
+
ffn_hidden=8960,
|
| 15 |
+
layer_pattern="SSSL",
|
| 16 |
+
gla_delta=True,
|
| 17 |
+
fno_modes=512,
|
| 18 |
+
gla_chunk=256,
|
| 19 |
+
landmark_layer_every=7,
|
| 20 |
+
landmark_chunk=32,
|
| 21 |
+
landmark_max=64,
|
| 22 |
+
attn_layer_every=0,
|
| 23 |
+
tie_word_embeddings=False,
|
| 24 |
+
use_cache=False,
|
| 25 |
+
**kwargs,
|
| 26 |
+
):
|
| 27 |
+
self.vocab_size = vocab_size
|
| 28 |
+
self.seq_len = seq_len
|
| 29 |
+
self.n_layer = n_layer
|
| 30 |
+
self.n_embd = n_embd
|
| 31 |
+
self.n_head = n_head
|
| 32 |
+
self.ffn_hidden = ffn_hidden
|
| 33 |
+
self.layer_pattern = layer_pattern
|
| 34 |
+
self.gla_delta = gla_delta
|
| 35 |
+
self.fno_modes = fno_modes
|
| 36 |
+
self.gla_chunk = gla_chunk
|
| 37 |
+
self.landmark_layer_every = landmark_layer_every
|
| 38 |
+
self.landmark_chunk = landmark_chunk
|
| 39 |
+
self.landmark_max = landmark_max
|
| 40 |
+
self.attn_layer_every = attn_layer_every
|
| 41 |
+
self.num_hidden_layers = n_layer
|
| 42 |
+
self.use_cache = use_cache
|
| 43 |
+
super().__init__(tie_word_embeddings=tie_word_embeddings, **kwargs)
|
cpu_delta.py
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
import torch
|
| 3 |
+
import torch.nn.functional as F
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
def gdn_recurrent(
|
| 7 |
+
q: torch.Tensor,
|
| 8 |
+
k: torch.Tensor,
|
| 9 |
+
v: torch.Tensor,
|
| 10 |
+
beta: torch.Tensor,
|
| 11 |
+
g: torch.Tensor,
|
| 12 |
+
scale: float,
|
| 13 |
+
initial_state: torch.Tensor | None = None,
|
| 14 |
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
| 15 |
+
q, k, v, beta, g = (
|
| 16 |
+
t.transpose(1, 2).contiguous().to(torch.float32) for t in (q, k, v, beta, g)
|
| 17 |
+
)
|
| 18 |
+
B, H, T, K = q.shape
|
| 19 |
+
V = v.shape[-1]
|
| 20 |
+
o = torch.zeros(B, H, T, V, dtype=torch.float32, device=q.device)
|
| 21 |
+
if initial_state is None:
|
| 22 |
+
h = torch.zeros(B, H, K, V, dtype=torch.float32, device=q.device)
|
| 23 |
+
else:
|
| 24 |
+
h = initial_state.to(torch.float32).clone()
|
| 25 |
+
q = q * scale
|
| 26 |
+
for i in range(T):
|
| 27 |
+
b_q = q[:, :, i]
|
| 28 |
+
b_k = k[:, :, i]
|
| 29 |
+
b_v = v[:, :, i].clone()
|
| 30 |
+
h = h * g[:, :, i].exp()[..., None, None]
|
| 31 |
+
b_v = b_v - (h * b_k[..., None]).sum(-2)
|
| 32 |
+
b_v = b_v * beta[:, :, i][..., None]
|
| 33 |
+
h = h + b_k.unsqueeze(-1) * b_v.unsqueeze(-2)
|
| 34 |
+
o[:, :, i] = torch.einsum("bhd,bhdm->bhm", b_q, h)
|
| 35 |
+
return (o.transpose(1, 2).contiguous(), h)
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def gdn_chunk_recurrent(
|
| 39 |
+
q: torch.Tensor,
|
| 40 |
+
k: torch.Tensor,
|
| 41 |
+
v: torch.Tensor,
|
| 42 |
+
beta: torch.Tensor,
|
| 43 |
+
g: torch.Tensor,
|
| 44 |
+
scale: float,
|
| 45 |
+
initial_state: torch.Tensor | None = None,
|
| 46 |
+
chunk_size: int = 64,
|
| 47 |
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
| 48 |
+
bt = chunk_size
|
| 49 |
+
q, k, v, beta, g = (
|
| 50 |
+
t.transpose(1, 2).contiguous().to(torch.float32) for t in (q, k, v, beta, g)
|
| 51 |
+
)
|
| 52 |
+
B, H, T, K = q.shape
|
| 53 |
+
Vd = v.shape[-1]
|
| 54 |
+
pad = (bt - T % bt) % bt
|
| 55 |
+
if pad:
|
| 56 |
+
q = F.pad(q, (0, 0, 0, pad))
|
| 57 |
+
k = F.pad(k, (0, 0, 0, pad))
|
| 58 |
+
v = F.pad(v, (0, 0, 0, pad))
|
| 59 |
+
beta = F.pad(beta, (0, pad))
|
| 60 |
+
g = F.pad(g, (0, pad))
|
| 61 |
+
L = q.shape[2]
|
| 62 |
+
n = L // bt
|
| 63 |
+
q = q * scale
|
| 64 |
+
v = v * beta[..., None]
|
| 65 |
+
k_beta = k * beta[..., None]
|
| 66 |
+
|
| 67 |
+
def _chunks(x):
|
| 68 |
+
return x.reshape(B, H, n, bt, x.shape[-1])
|
| 69 |
+
|
| 70 |
+
q, k, v, k_beta = (_chunks(q), _chunks(k), _chunks(v), _chunks(k_beta))
|
| 71 |
+
decay = g.reshape(B, H, n, bt).cumsum(-1)
|
| 72 |
+
decay_exp = decay.exp()[..., None]
|
| 73 |
+
l_mask = (decay.unsqueeze(-1) - decay.unsqueeze(-2)).tril().exp().tril()
|
| 74 |
+
eye_mask = torch.triu(
|
| 75 |
+
torch.ones(bt, bt, dtype=torch.bool, device=q.device), diagonal=0
|
| 76 |
+
)
|
| 77 |
+
attn = -(k_beta @ k.transpose(-1, -2) * l_mask).masked_fill(eye_mask, 0)
|
| 78 |
+
for i in range(1, bt):
|
| 79 |
+
attn[..., i, :i] = attn[..., i, :i].clone() + (
|
| 80 |
+
attn[..., i, :i, None].clone() * attn[..., :i, :i].clone()
|
| 81 |
+
).sum(-2)
|
| 82 |
+
attn = attn + torch.eye(bt, dtype=torch.float32, device=q.device)
|
| 83 |
+
v = attn @ v
|
| 84 |
+
k_cumdecay = attn @ (k_beta * decay_exp)
|
| 85 |
+
S = q.new_zeros(B, H, K, Vd)
|
| 86 |
+
if initial_state is not None:
|
| 87 |
+
S = initial_state.to(torch.float32).clone()
|
| 88 |
+
o = torch.zeros_like(v)
|
| 89 |
+
causal = torch.triu(
|
| 90 |
+
torch.ones(bt, bt, dtype=torch.bool, device=q.device), diagonal=1
|
| 91 |
+
)
|
| 92 |
+
for i in range(n):
|
| 93 |
+
q_i, k_i, v_i = (q[:, :, i], k[:, :, i], v[:, :, i])
|
| 94 |
+
a_i = (q_i @ k_i.transpose(-1, -2) * l_mask[:, :, i]).masked_fill(causal, 0)
|
| 95 |
+
v_new = v_i - k_cumdecay[:, :, i] @ S
|
| 96 |
+
o_inter = q_i * decay[:, :, i, :, None].exp() @ S
|
| 97 |
+
o[:, :, i] = o_inter + a_i @ v_new
|
| 98 |
+
S = (
|
| 99 |
+
S * decay[:, :, i, -1, None, None].exp()
|
| 100 |
+
+ (
|
| 101 |
+
k_i * (decay[:, :, i, -1, None] - decay[:, :, i]).exp()[..., None]
|
| 102 |
+
).transpose(-1, -2)
|
| 103 |
+
@ v_new
|
| 104 |
+
)
|
| 105 |
+
o = o.reshape(B, H, L, Vd)[:, :, :T]
|
| 106 |
+
return (o.transpose(1, 2).contiguous(), S)
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
def causal_depthwise_conv1d(
|
| 110 |
+
x: torch.Tensor,
|
| 111 |
+
weight: torch.Tensor,
|
| 112 |
+
bias: torch.Tensor | None = None,
|
| 113 |
+
activation: str | None = "silu",
|
| 114 |
+
) -> torch.Tensor:
|
| 115 |
+
B, T, C = x.shape
|
| 116 |
+
W = weight.shape[-1]
|
| 117 |
+
xt = x.transpose(1, 2)
|
| 118 |
+
xp = F.pad(xt, (W - 1, 0))
|
| 119 |
+
y = F.conv1d(xp, weight, bias=bias, groups=C)[..., :T].transpose(1, 2)
|
| 120 |
+
if activation == "silu":
|
| 121 |
+
y = F.silu(y)
|
| 122 |
+
elif activation is not None:
|
| 123 |
+
raise ValueError(f"unsupported activation {activation!r}")
|
| 124 |
+
return y
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
def _conv_chunk(
|
| 128 |
+
p: torch.Tensor,
|
| 129 |
+
weight: torch.Tensor,
|
| 130 |
+
conv_state: torch.Tensor | None,
|
| 131 |
+
bias: torch.Tensor | None = None,
|
| 132 |
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
| 133 |
+
B, L, C = p.shape
|
| 134 |
+
W = weight.shape[-1]
|
| 135 |
+
pt = p.transpose(1, 2)
|
| 136 |
+
if conv_state is None:
|
| 137 |
+
conv_state = pt.new_zeros(B, C, W - 1)
|
| 138 |
+
full = torch.cat([conv_state, pt], dim=-1)
|
| 139 |
+
y = F.silu(F.conv1d(full, weight, bias=bias, groups=C)).transpose(1, 2)
|
| 140 |
+
return (y, full[..., -(W - 1) :])
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
def gdn_gate(
|
| 144 |
+
g: torch.Tensor, A_log: torch.Tensor, dt_bias: torch.Tensor | None = None
|
| 145 |
+
) -> torch.Tensor:
|
| 146 |
+
g = g.float()
|
| 147 |
+
if dt_bias is not None:
|
| 148 |
+
g = g + dt_bias.float()
|
| 149 |
+
return -A_log.float().exp() * F.softplus(g)
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
def gated_rmsnorm(
|
| 153 |
+
o: torch.Tensor, gate: torch.Tensor, weight: torch.Tensor, eps: float = 1e-05
|
| 154 |
+
) -> torch.Tensor:
|
| 155 |
+
o = o.float()
|
| 156 |
+
gate = gate.float()
|
| 157 |
+
rstd = torch.rsqrt(o.pow(2).mean(-1, keepdim=True) + eps)
|
| 158 |
+
return o * rstd * weight.float() * (gate * torch.sigmoid(gate))
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
class CPUGatedDeltaNet:
|
| 162 |
+
def __init__(self, gdn):
|
| 163 |
+
self.gdn = gdn
|
| 164 |
+
self.H = gdn.num_heads
|
| 165 |
+
self.Dk = gdn.head_k_dim
|
| 166 |
+
self.Dv = gdn.head_v_dim
|
| 167 |
+
self.C = gdn.value_dim
|
| 168 |
+
self.W = gdn.conv_size
|
| 169 |
+
self.scale = self.Dk ** (-0.5)
|
| 170 |
+
self.eps = getattr(gdn.o_norm, "eps", 1e-05)
|
| 171 |
+
self.chunk_size = 64
|
| 172 |
+
assert not gdn.allow_neg_eigval, "allow_neg_eigval not supported"
|
| 173 |
+
assert gdn.use_gate and gdn.use_short_conv
|
| 174 |
+
|
| 175 |
+
def _project(self, x, conv_state):
|
| 176 |
+
g = self.gdn
|
| 177 |
+
q, sq = _conv_chunk(
|
| 178 |
+
g.q_proj(x),
|
| 179 |
+
g.q_conv1d.weight,
|
| 180 |
+
None if conv_state is None else conv_state[0],
|
| 181 |
+
)
|
| 182 |
+
k, sk = _conv_chunk(
|
| 183 |
+
g.k_proj(x),
|
| 184 |
+
g.k_conv1d.weight,
|
| 185 |
+
None if conv_state is None else conv_state[1],
|
| 186 |
+
)
|
| 187 |
+
v, sv = _conv_chunk(
|
| 188 |
+
g.v_proj(x),
|
| 189 |
+
g.v_conv1d.weight,
|
| 190 |
+
None if conv_state is None else conv_state[2],
|
| 191 |
+
)
|
| 192 |
+
B, L = (x.shape[0], x.shape[1])
|
| 193 |
+
q = F.normalize(q.view(B, L, self.H, self.Dk), p=2, dim=-1)
|
| 194 |
+
k = F.normalize(k.view(B, L, self.H, self.Dk), p=2, dim=-1)
|
| 195 |
+
v = v.view(B, L, self.H, self.Dv)
|
| 196 |
+
beta = torch.sigmoid(g.b_proj(x))
|
| 197 |
+
gate_g = gdn_gate(g.a_proj(x), g.A_log, g.dt_bias)
|
| 198 |
+
return (q, k, v, beta, gate_g, (sq, sk, sv))
|
| 199 |
+
|
| 200 |
+
def _output(self, o, x):
|
| 201 |
+
g = self.gdn
|
| 202 |
+
B, L = (x.shape[0], x.shape[1])
|
| 203 |
+
gate = g.g_proj(x).view(B, L, self.H, self.Dv)
|
| 204 |
+
o = gated_rmsnorm(o, gate, g.o_norm.weight, self.eps)
|
| 205 |
+
o = o.reshape(B, L, self.C)
|
| 206 |
+
return g.o_proj(o)
|
| 207 |
+
|
| 208 |
+
def init_state(self, batch_size: int = 1, device=None):
|
| 209 |
+
if device is None:
|
| 210 |
+
device = self.gdn.q_proj.weight.device
|
| 211 |
+
return {
|
| 212 |
+
"recurrent_state": torch.zeros(
|
| 213 |
+
batch_size, self.H, self.Dk, self.Dv, device=device
|
| 214 |
+
),
|
| 215 |
+
"conv": tuple(
|
| 216 |
+
(
|
| 217 |
+
torch.zeros(batch_size, self.C, self.W - 1, device=device)
|
| 218 |
+
for _ in range(3)
|
| 219 |
+
)
|
| 220 |
+
),
|
| 221 |
+
}
|
| 222 |
+
|
| 223 |
+
def _recurrence(self, q, k, v, beta, g, initial_state):
|
| 224 |
+
if q.shape[1] >= self.chunk_size:
|
| 225 |
+
return gdn_chunk_recurrent(
|
| 226 |
+
q,
|
| 227 |
+
k,
|
| 228 |
+
v,
|
| 229 |
+
beta,
|
| 230 |
+
g,
|
| 231 |
+
self.scale,
|
| 232 |
+
initial_state=initial_state,
|
| 233 |
+
chunk_size=self.chunk_size,
|
| 234 |
+
)
|
| 235 |
+
return gdn_recurrent(q, k, v, beta, g, self.scale, initial_state=initial_state)
|
| 236 |
+
|
| 237 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 238 |
+
q, k, v, beta, gate_g, _ = self._project(x, None)
|
| 239 |
+
o, _ = self._recurrence(q, k, v, beta, gate_g, initial_state=None)
|
| 240 |
+
return self._output(o, x).to(x.dtype)
|
| 241 |
+
|
| 242 |
+
def forward_chunk(self, x: torch.Tensor, state):
|
| 243 |
+
conv_state = None if state is None else state["conv"]
|
| 244 |
+
rec = None if state is None else state["recurrent_state"]
|
| 245 |
+
q, k, v, beta, gate_g, new_conv = self._project(x, conv_state)
|
| 246 |
+
o, rec = self._recurrence(q, k, v, beta, gate_g, initial_state=rec)
|
| 247 |
+
return (
|
| 248 |
+
self._output(o, x).to(x.dtype),
|
| 249 |
+
{"recurrent_state": rec, "conv": new_conv},
|
| 250 |
+
)
|
| 251 |
+
|
| 252 |
+
def step(self, x: torch.Tensor, state):
|
| 253 |
+
if x.dim() == 2:
|
| 254 |
+
x = x.unsqueeze(1)
|
| 255 |
+
o, state = self.forward_chunk(x, state)
|
| 256 |
+
return (o.squeeze(1), state)
|
cpu_landmark.py
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
import torch
|
| 3 |
+
import torch.nn.functional as F
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
class CPULandmark:
|
| 7 |
+
def __init__(self, mixer):
|
| 8 |
+
self.mixer = mixer
|
| 9 |
+
self.H = mixer.n_head
|
| 10 |
+
self.D = mixer.d_head
|
| 11 |
+
self.C = self.H * self.D
|
| 12 |
+
self.chunk = mixer.chunk
|
| 13 |
+
self.max_land = mixer.max_land
|
| 14 |
+
|
| 15 |
+
def init_state(self, batch_size: int = 1, device=None, c: int | None = None):
|
| 16 |
+
if device is None:
|
| 17 |
+
device = self.mixer.q_proj.weight.device
|
| 18 |
+
return {
|
| 19 |
+
"k": torch.zeros(batch_size, self.max_land, self.H, self.D, device=device),
|
| 20 |
+
"v": torch.zeros(batch_size, self.max_land, self.H, self.D, device=device),
|
| 21 |
+
"n_land": torch.zeros(batch_size, dtype=torch.long, device=device),
|
| 22 |
+
"acc_sum": torch.zeros(batch_size, self.C, device=device),
|
| 23 |
+
"acc_cnt": torch.zeros(batch_size, dtype=torch.long, device=device),
|
| 24 |
+
"c": int(c) if c else self.chunk,
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
def _sink_kv(self, batch_size: int, device):
|
| 28 |
+
sink = self.mixer.sink
|
| 29 |
+
sk = self.mixer.k_proj(sink).reshape(1, 1, self.H, self.D)
|
| 30 |
+
sv = self.mixer.v_proj(sink).reshape(1, 1, self.H, self.D)
|
| 31 |
+
exp = (batch_size, 1, self.H, self.D)
|
| 32 |
+
return (sk.to(device).expand(*exp), sv.to(device).expand(*exp))
|
| 33 |
+
|
| 34 |
+
def step(self, x: torch.Tensor, state):
|
| 35 |
+
if x.dim() == 3:
|
| 36 |
+
x = x.squeeze(1)
|
| 37 |
+
B = x.shape[0]
|
| 38 |
+
if state is None:
|
| 39 |
+
state = self.init_state(B, device=x.device)
|
| 40 |
+
c = state["c"]
|
| 41 |
+
n = state["n_land"]
|
| 42 |
+
Lmax = self.max_land
|
| 43 |
+
sk, sv = self._sink_kv(B, x.device)
|
| 44 |
+
keys = torch.cat([sk, state["k"]], dim=1)
|
| 45 |
+
vals = torch.cat([sv, state["v"]], dim=1)
|
| 46 |
+
idx = torch.arange(Lmax, device=x.device)[None, :]
|
| 47 |
+
valid = torch.cat(
|
| 48 |
+
[torch.ones(B, 1, dtype=torch.bool, device=x.device), idx < n[:, None]],
|
| 49 |
+
dim=1,
|
| 50 |
+
)
|
| 51 |
+
q = self.mixer.q_proj(x).reshape(B, 1, self.H, self.D).transpose(1, 2)
|
| 52 |
+
o = F.scaled_dot_product_attention(
|
| 53 |
+
q,
|
| 54 |
+
keys.transpose(1, 2),
|
| 55 |
+
vals.transpose(1, 2),
|
| 56 |
+
attn_mask=valid[:, None, None, :],
|
| 57 |
+
)
|
| 58 |
+
o = self.mixer.o_proj(o.transpose(1, 2).reshape(B, self.C))
|
| 59 |
+
acc_sum = state["acc_sum"] + x
|
| 60 |
+
acc_cnt = state["acc_cnt"] + 1
|
| 61 |
+
k, v = (state["k"].clone(), state["v"].clone())
|
| 62 |
+
fin = acc_cnt == c
|
| 63 |
+
if bool(fin.any()):
|
| 64 |
+
mean = acc_sum / c
|
| 65 |
+
lk = self.mixer.k_proj(mean).reshape(B, self.H, self.D)
|
| 66 |
+
lv = self.mixer.v_proj(mean).reshape(B, self.H, self.D)
|
| 67 |
+
rows = torch.arange(B, device=x.device)
|
| 68 |
+
full = fin & (n >= Lmax)
|
| 69 |
+
if bool(full.any()):
|
| 70 |
+
k[full] = torch.cat([k[full][:, 1:], k[full][:, :1]], dim=1)
|
| 71 |
+
v[full] = torch.cat([v[full][:, 1:], v[full][:, :1]], dim=1)
|
| 72 |
+
write_pos = n.clamp(max=Lmax - 1)
|
| 73 |
+
fr, wp = (rows[fin], write_pos[fin])
|
| 74 |
+
k[fr, wp] = lk[fr]
|
| 75 |
+
v[fr, wp] = lv[fr]
|
| 76 |
+
n = (n + fin.long()).clamp(max=Lmax)
|
| 77 |
+
acc_sum = torch.where(fin[:, None], torch.zeros_like(acc_sum), acc_sum)
|
| 78 |
+
acc_cnt = torch.where(fin, torch.zeros_like(acc_cnt), acc_cnt)
|
| 79 |
+
return (
|
| 80 |
+
o,
|
| 81 |
+
{
|
| 82 |
+
"k": k,
|
| 83 |
+
"v": v,
|
| 84 |
+
"n_land": n,
|
| 85 |
+
"acc_sum": acc_sum,
|
| 86 |
+
"acc_cnt": acc_cnt,
|
| 87 |
+
"c": c,
|
| 88 |
+
},
|
| 89 |
+
)
|
| 90 |
+
|
| 91 |
+
def forward_chunk(self, x: torch.Tensor, state):
|
| 92 |
+
B, L, _ = x.shape
|
| 93 |
+
if state is None:
|
| 94 |
+
state = self.init_state(B, device=x.device)
|
| 95 |
+
outs = []
|
| 96 |
+
for i in range(L):
|
| 97 |
+
o, state = self.step(x[:, i], state)
|
| 98 |
+
outs.append(o)
|
| 99 |
+
return (torch.stack(outs, dim=1), state)
|
cpu_patch.py
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
import types
|
| 3 |
+
import importlib
|
| 4 |
+
import torch
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def _sib(mod, *names):
|
| 8 |
+
try:
|
| 9 |
+
m = importlib.import_module("." + mod, __package__ or None)
|
| 10 |
+
except (ImportError, TypeError, ValueError):
|
| 11 |
+
m = importlib.import_module(mod)
|
| 12 |
+
return [getattr(m, n) for n in names]
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
(CPUGatedDeltaNet,) = _sib("cpu_delta", "CPUGatedDeltaNet")
|
| 16 |
+
(CPULandmark,) = _sib("cpu_landmark", "CPULandmark")
|
| 17 |
+
CPUSlidingWindow, swa_fused_forward = _sib(
|
| 18 |
+
"cpu_swa", "CPUSlidingWindow", "swa_fused_forward"
|
| 19 |
+
)
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def _is_delta_block(block) -> bool:
|
| 23 |
+
return (
|
| 24 |
+
getattr(block, "is_gla", False)
|
| 25 |
+
and getattr(block.mixer, "gla_delta", False)
|
| 26 |
+
and hasattr(block.mixer, "gdn")
|
| 27 |
+
)
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def _is_landmark_block(block) -> bool:
|
| 31 |
+
return getattr(block, "is_landmark", False)
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def _has_swa_fused(block) -> bool:
|
| 35 |
+
return int(getattr(block.mixer, "swa_fused_window", 0)) > 0
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def _make_block_methods(cpu_gdn, cpu_swa):
|
| 39 |
+
|
| 40 |
+
def step(self, x, bstate):
|
| 41 |
+
h = self.ln1(x)
|
| 42 |
+
if cpu_swa is not None:
|
| 43 |
+
h, bstate["swa"] = cpu_swa.step(h, bstate.get("swa"))
|
| 44 |
+
if h.dim() == 2:
|
| 45 |
+
h = h.unsqueeze(1)
|
| 46 |
+
o, bstate["gdn"] = cpu_gdn.step(h, bstate.get("gdn"))
|
| 47 |
+
x = x + o
|
| 48 |
+
x = x + self.ffn(self.ln2(x))
|
| 49 |
+
return (x, bstate)
|
| 50 |
+
|
| 51 |
+
def forward_chunk(self, x, bstate):
|
| 52 |
+
h = self.ln1(x)
|
| 53 |
+
if cpu_swa is not None:
|
| 54 |
+
h, bstate["swa"] = cpu_swa.forward_chunk(h, bstate.get("swa"))
|
| 55 |
+
o, bstate["gdn"] = cpu_gdn.forward_chunk(h, bstate.get("gdn"))
|
| 56 |
+
x = x + o
|
| 57 |
+
x = x + self.ffn(self.ln2(x))
|
| 58 |
+
return (x, bstate)
|
| 59 |
+
|
| 60 |
+
return (step, forward_chunk)
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
def _make_landmark_block_methods(cpu_land):
|
| 64 |
+
|
| 65 |
+
def step(self, x, bstate):
|
| 66 |
+
h = self.ln1(x)
|
| 67 |
+
o, bstate["land"] = cpu_land.step(h, bstate.get("land"))
|
| 68 |
+
x = x + o
|
| 69 |
+
x = x + self.ffn(self.ln2(x))
|
| 70 |
+
return (x, bstate)
|
| 71 |
+
|
| 72 |
+
def forward_chunk(self, x, bstate):
|
| 73 |
+
h = self.ln1(x)
|
| 74 |
+
o, bstate["land"] = cpu_land.forward_chunk(h, bstate.get("land"))
|
| 75 |
+
x = x + o
|
| 76 |
+
x = x + self.ffn(self.ln2(x))
|
| 77 |
+
return (x, bstate)
|
| 78 |
+
|
| 79 |
+
return (step, forward_chunk)
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def _make_mixer_forward(cpu_gdn, cpu_swa, orig_forward):
|
| 83 |
+
|
| 84 |
+
def forward(self, x):
|
| 85 |
+
if x.is_cuda:
|
| 86 |
+
return orig_forward(x)
|
| 87 |
+
if cpu_swa is not None:
|
| 88 |
+
x = swa_fused_forward(self, x)
|
| 89 |
+
return cpu_gdn.forward(x)
|
| 90 |
+
|
| 91 |
+
return forward
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
def _make_init_state(model):
|
| 95 |
+
cfg = model.cfg
|
| 96 |
+
H = cfg.n_head
|
| 97 |
+
D = cfg.n_embd // H
|
| 98 |
+
M = cfg.fno_modes
|
| 99 |
+
C = cfg.n_embd
|
| 100 |
+
|
| 101 |
+
def init_state(self, batch_size: int = 1, device=None):
|
| 102 |
+
if device is None:
|
| 103 |
+
device = next(self.parameters()).device
|
| 104 |
+
states = []
|
| 105 |
+
for block in self.blocks:
|
| 106 |
+
if _is_delta_block(block):
|
| 107 |
+
states.append(
|
| 108 |
+
{"swa": None, "gdn": None}
|
| 109 |
+
if _has_swa_fused(block)
|
| 110 |
+
else {"gdn": None}
|
| 111 |
+
)
|
| 112 |
+
elif _is_landmark_block(block):
|
| 113 |
+
states.append({"land": None})
|
| 114 |
+
elif block.is_gla:
|
| 115 |
+
states.append(
|
| 116 |
+
{
|
| 117 |
+
"gla_state": torch.zeros(batch_size, H, D, D, device=device),
|
| 118 |
+
"z_norm": torch.zeros(batch_size, H, D, device=device),
|
| 119 |
+
}
|
| 120 |
+
)
|
| 121 |
+
else:
|
| 122 |
+
states.append(
|
| 123 |
+
{"buf": torch.zeros(batch_size, M, C, device=device), "pos": 0}
|
| 124 |
+
)
|
| 125 |
+
return states
|
| 126 |
+
|
| 127 |
+
return init_state
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
def enable_cpu_delta(model) -> int:
|
| 131 |
+
n = 0
|
| 132 |
+
for block in model.blocks:
|
| 133 |
+
if _is_delta_block(block):
|
| 134 |
+
cpu_gdn = CPUGatedDeltaNet(block.mixer.gdn)
|
| 135 |
+
cpu_swa = CPUSlidingWindow(block.mixer) if _has_swa_fused(block) else None
|
| 136 |
+
step, forward_chunk = _make_block_methods(cpu_gdn, cpu_swa)
|
| 137 |
+
block.step = types.MethodType(step, block)
|
| 138 |
+
block.forward_chunk = types.MethodType(forward_chunk, block)
|
| 139 |
+
block.mixer.forward = types.MethodType(
|
| 140 |
+
_make_mixer_forward(cpu_gdn, cpu_swa, block.mixer.forward), block.mixer
|
| 141 |
+
)
|
| 142 |
+
block.mixer._cpu_gdn = cpu_gdn
|
| 143 |
+
block.mixer._cpu_swa = cpu_swa
|
| 144 |
+
n += 1
|
| 145 |
+
elif _is_landmark_block(block):
|
| 146 |
+
cpu_land = CPULandmark(block.mixer)
|
| 147 |
+
step, forward_chunk = _make_landmark_block_methods(cpu_land)
|
| 148 |
+
block.step = types.MethodType(step, block)
|
| 149 |
+
block.forward_chunk = types.MethodType(forward_chunk, block)
|
| 150 |
+
block.mixer._cpu_land = cpu_land
|
| 151 |
+
if not hasattr(block.mixer, "prepare_inference"):
|
| 152 |
+
block.mixer.prepare_inference = types.MethodType(
|
| 153 |
+
lambda self: None, block.mixer
|
| 154 |
+
)
|
| 155 |
+
n += 1
|
| 156 |
+
model.init_state = types.MethodType(_make_init_state(model), model)
|
| 157 |
+
return n
|
cpu_swa.py
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
import torch
|
| 3 |
+
import torch.nn.functional as F
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
def banded_softmax_attention(
|
| 7 |
+
q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, w: int
|
| 8 |
+
) -> torch.Tensor:
|
| 9 |
+
T = q.shape[-2]
|
| 10 |
+
i = torch.arange(T, device=q.device)[:, None]
|
| 11 |
+
j = torch.arange(T, device=q.device)[None, :]
|
| 12 |
+
mask = (j <= i) & (j > i - w)
|
| 13 |
+
return F.scaled_dot_product_attention(q, k, v, attn_mask=mask)
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def swa_fused_forward(mixer, x: torch.Tensor) -> torch.Tensor:
|
| 17 |
+
B, T, C = x.shape
|
| 18 |
+
H, w = (mixer.n_head, mixer.swa_fused_window)
|
| 19 |
+
D = C // H
|
| 20 |
+
q = mixer.swa_fused_q(x).reshape(B, T, H, D).transpose(1, 2)
|
| 21 |
+
k = mixer.swa_fused_k(x).reshape(B, T, H, D).transpose(1, 2)
|
| 22 |
+
v = mixer.swa_fused_v(x).reshape(B, T, H, D).transpose(1, 2)
|
| 23 |
+
o = banded_softmax_attention(q, k, v, w)
|
| 24 |
+
o = o.transpose(1, 2).reshape(B, T, C)
|
| 25 |
+
return x + mixer.swa_fused_o(o)
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
class CPUSlidingWindow:
|
| 29 |
+
def __init__(self, mixer):
|
| 30 |
+
self.mixer = mixer
|
| 31 |
+
self.H = mixer.n_head
|
| 32 |
+
self.C = mixer.swa_fused_q.out_features
|
| 33 |
+
self.D = self.C // self.H
|
| 34 |
+
self.w = mixer.swa_fused_window
|
| 35 |
+
self.scale = self.D ** (-0.5)
|
| 36 |
+
|
| 37 |
+
def init_state(self, batch_size: int = 1, device=None):
|
| 38 |
+
if device is None:
|
| 39 |
+
device = self.mixer.swa_fused_q.weight.device
|
| 40 |
+
W1 = self.w - 1
|
| 41 |
+
return {
|
| 42 |
+
"k": torch.zeros(batch_size, W1, self.H, self.D, device=device),
|
| 43 |
+
"v": torch.zeros(batch_size, W1, self.H, self.D, device=device),
|
| 44 |
+
"n": 0,
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
def _project(self, x):
|
| 48 |
+
B, L, _ = x.shape
|
| 49 |
+
q = self.mixer.swa_fused_q(x).reshape(B, L, self.H, self.D)
|
| 50 |
+
k = self.mixer.swa_fused_k(x).reshape(B, L, self.H, self.D)
|
| 51 |
+
v = self.mixer.swa_fused_v(x).reshape(B, L, self.H, self.D)
|
| 52 |
+
return (q, k, v)
|
| 53 |
+
|
| 54 |
+
def forward_chunk(self, x: torch.Tensor, state):
|
| 55 |
+
B, L, C = x.shape
|
| 56 |
+
w = self.w
|
| 57 |
+
if state is None:
|
| 58 |
+
state = self.init_state(B, device=x.device)
|
| 59 |
+
n = state["n"]
|
| 60 |
+
W1 = w - 1
|
| 61 |
+
ck = state["k"][:, W1 - n :, :, :] if n > 0 else state["k"][:, :0]
|
| 62 |
+
cv = state["v"][:, W1 - n :, :, :] if n > 0 else state["v"][:, :0]
|
| 63 |
+
q, k, v = self._project(x)
|
| 64 |
+
k_all = torch.cat([ck, k], dim=1)
|
| 65 |
+
v_all = torch.cat([cv, v], dim=1)
|
| 66 |
+
Tk = n + L
|
| 67 |
+
iq = torch.arange(L, device=x.device)[:, None] + n
|
| 68 |
+
jk = torch.arange(Tk, device=x.device)[None, :]
|
| 69 |
+
mask = (jk <= iq) & (jk > iq - w)
|
| 70 |
+
qh = q.transpose(1, 2)
|
| 71 |
+
kh = k_all.transpose(1, 2)
|
| 72 |
+
vh = v_all.transpose(1, 2)
|
| 73 |
+
o = F.scaled_dot_product_attention(qh, kh, vh, attn_mask=mask)
|
| 74 |
+
o = o.transpose(1, 2).reshape(B, L, C)
|
| 75 |
+
out = x + self.mixer.swa_fused_o(o)
|
| 76 |
+
keep = min(W1, Tk)
|
| 77 |
+
new_k = state["k"].clone()
|
| 78 |
+
new_v = state["v"].clone()
|
| 79 |
+
if keep > 0:
|
| 80 |
+
new_k[:, W1 - keep :, :, :] = k_all[:, Tk - keep :, :, :]
|
| 81 |
+
new_v[:, W1 - keep :, :, :] = v_all[:, Tk - keep :, :, :]
|
| 82 |
+
new_state = {"k": new_k, "v": new_v, "n": keep}
|
| 83 |
+
return (out, new_state)
|
| 84 |
+
|
| 85 |
+
def step(self, x: torch.Tensor, state):
|
| 86 |
+
if x.dim() == 2:
|
| 87 |
+
x = x.unsqueeze(1)
|
| 88 |
+
o, state = self.forward_chunk(x, state)
|
| 89 |
+
return (o.squeeze(1), state)
|
model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:0edb28e43cd050f22d6960421f0c359ad23778136929285254cbb2ab084d28a9
|
| 3 |
+
size 3576787488
|
model_cpu_gpt2.py
ADDED
|
@@ -0,0 +1,1262 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
import os
|
| 3 |
+
from dataclasses import dataclass
|
| 4 |
+
from typing import Optional
|
| 5 |
+
import torch
|
| 6 |
+
import torch.nn as nn
|
| 7 |
+
import torch.nn.functional as F
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def _detect_cpu_bf16() -> bool:
|
| 11 |
+
try:
|
| 12 |
+
with open("/proc/cpuinfo") as f:
|
| 13 |
+
return "avx512_bf16" in f.read()
|
| 14 |
+
except Exception:
|
| 15 |
+
return False
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
_CPU_HAS_BF16: bool = _detect_cpu_bf16()
|
| 19 |
+
try:
|
| 20 |
+
import pyfftw
|
| 21 |
+
|
| 22 |
+
pyfftw.interfaces.cache.enable()
|
| 23 |
+
pyfftw.interfaces.cache.set_keepalive_time(60.0)
|
| 24 |
+
except ImportError:
|
| 25 |
+
pass
|
| 26 |
+
try:
|
| 27 |
+
if os.environ.get("NO_CPP_EXT"):
|
| 28 |
+
raise ImportError("C++ extensions disabled via NO_CPP_EXT")
|
| 29 |
+
import torch.utils.cpp_extension as _cpp_ext
|
| 30 |
+
|
| 31 |
+
_ext_path = os.path.join(os.path.dirname(__file__), "csrc")
|
| 32 |
+
_gla_ext = (
|
| 33 |
+
_cpp_ext.load(
|
| 34 |
+
name="gla_scan_cpu",
|
| 35 |
+
sources=[os.path.join(_ext_path, "gla_scan.cpp")],
|
| 36 |
+
extra_cflags=["-O3", "-fopenmp", "-march=native"],
|
| 37 |
+
extra_ldflags=["-fopenmp"],
|
| 38 |
+
verbose=False,
|
| 39 |
+
)
|
| 40 |
+
if os.path.exists(os.path.join(_ext_path, "gla_scan.cpp"))
|
| 41 |
+
else None
|
| 42 |
+
)
|
| 43 |
+
except Exception:
|
| 44 |
+
_gla_ext = None
|
| 45 |
+
try:
|
| 46 |
+
if os.environ.get("NO_CPP_EXT"):
|
| 47 |
+
raise ImportError("C++ extensions disabled via NO_CPP_EXT")
|
| 48 |
+
import torch.utils.cpp_extension as _fno_cpp_ext
|
| 49 |
+
|
| 50 |
+
_fno_ext_src = os.path.join(os.path.dirname(__file__), "csrc", "fno_conv.cpp")
|
| 51 |
+
_fno_ext = (
|
| 52 |
+
_fno_cpp_ext.load(
|
| 53 |
+
name="fno_conv_cpu",
|
| 54 |
+
sources=[_fno_ext_src],
|
| 55 |
+
extra_cflags=["-O3", "-fopenmp", "-march=native"],
|
| 56 |
+
extra_ldflags=["-fopenmp"],
|
| 57 |
+
verbose=False,
|
| 58 |
+
)
|
| 59 |
+
if os.path.exists(_fno_ext_src)
|
| 60 |
+
else None
|
| 61 |
+
)
|
| 62 |
+
except Exception:
|
| 63 |
+
_fno_ext = None
|
| 64 |
+
try:
|
| 65 |
+
from flashfftconv import FlashFFTConv as _FlashFFTConv
|
| 66 |
+
|
| 67 |
+
_flash_fft_available = True
|
| 68 |
+
except ImportError:
|
| 69 |
+
_FlashFFTConv = None
|
| 70 |
+
_flash_fft_available = False
|
| 71 |
+
try:
|
| 72 |
+
from fla.ops.gla import chunk_gla as _fla_chunk_gla
|
| 73 |
+
|
| 74 |
+
_fla_available = True
|
| 75 |
+
try:
|
| 76 |
+
from fla.ops import chunk_gated_delta_rule as _fla_chunk_gdr
|
| 77 |
+
from fla.layers import GatedDeltaNet as _FlaGatedDeltaNet
|
| 78 |
+
except Exception:
|
| 79 |
+
_fla_chunk_gdr = None
|
| 80 |
+
_FlaGatedDeltaNet = None
|
| 81 |
+
except ImportError:
|
| 82 |
+
_fla_chunk_gla = None
|
| 83 |
+
_fla_chunk_gdr = None
|
| 84 |
+
_FlaGatedDeltaNet = None
|
| 85 |
+
_fla_available = False
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
def _fft_dtype_to_torch(fft_dtype: str):
|
| 89 |
+
return {"fp32": torch.float32, "bf16": torch.bfloat16, "fp16": torch.float16}[
|
| 90 |
+
fft_dtype
|
| 91 |
+
]
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
def _gla_scan_py(q_k, k_k, v_f, chunk_gate, CS):
|
| 95 |
+
B, H, T, D = q_k.shape
|
| 96 |
+
n_chunks = T // CS
|
| 97 |
+
bf16 = q_k.dtype == torch.bfloat16
|
| 98 |
+
q_c = q_k.reshape(B, H, n_chunks, CS, D)
|
| 99 |
+
k_c = k_k.reshape(B, H, n_chunks, CS, D)
|
| 100 |
+
v_c = v_f.reshape(B, H, n_chunks, CS, D)
|
| 101 |
+
state = torch.zeros(B, H, D, D, device=q_k.device, dtype=torch.float32)
|
| 102 |
+
z_norm = torch.zeros(B, H, D, device=q_k.device, dtype=torch.float32)
|
| 103 |
+
chunks = []
|
| 104 |
+
for c in range(n_chunks):
|
| 105 |
+
if bf16:
|
| 106 |
+
num = q_c[:, :, c] @ state.bfloat16()
|
| 107 |
+
den = (q_c[:, :, c] @ z_norm.bfloat16().unsqueeze(-1)).clamp(min=1.0)
|
| 108 |
+
chunks.append(num / den)
|
| 109 |
+
g = chunk_gate[:, :, c, None, None]
|
| 110 |
+
state = g * state + (k_c[:, :, c].transpose(-2, -1) @ v_c[:, :, c]).float()
|
| 111 |
+
z_norm = chunk_gate[:, :, c, None] * z_norm + k_c[:, :, c].sum(-2).float()
|
| 112 |
+
else:
|
| 113 |
+
num = q_c[:, :, c] @ state
|
| 114 |
+
den = (q_c[:, :, c] @ z_norm.unsqueeze(-1)).clamp(min=1.0)
|
| 115 |
+
chunks.append(num / den)
|
| 116 |
+
g = chunk_gate[:, :, c, None, None]
|
| 117 |
+
state = g * state + k_c[:, :, c].transpose(-2, -1) @ v_c[:, :, c]
|
| 118 |
+
z_norm = chunk_gate[:, :, c, None] * z_norm + k_c[:, :, c].sum(dim=-2)
|
| 119 |
+
return torch.cat(chunks, dim=2)
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
@torch.compiler.disable
|
| 123 |
+
class _GLAScanFn(torch.autograd.Function):
|
| 124 |
+
@staticmethod
|
| 125 |
+
def forward(ctx, q_k, k_k, v_f, chunk_gate, CS):
|
| 126 |
+
ctx.CS = CS
|
| 127 |
+
with torch.no_grad():
|
| 128 |
+
out, states, z_norms = _gla_ext.gla_scan_fwd(
|
| 129 |
+
q_k.contiguous(),
|
| 130 |
+
k_k.contiguous(),
|
| 131 |
+
v_f.contiguous(),
|
| 132 |
+
chunk_gate.contiguous(),
|
| 133 |
+
CS,
|
| 134 |
+
)
|
| 135 |
+
ctx.save_for_backward(q_k, k_k, v_f, chunk_gate, states, z_norms)
|
| 136 |
+
return out
|
| 137 |
+
|
| 138 |
+
@staticmethod
|
| 139 |
+
def backward(ctx, grad_out):
|
| 140 |
+
q_k, k_k, v_f, chunk_gate, states, z_norms = ctx.saved_tensors
|
| 141 |
+
CS = ctx.CS
|
| 142 |
+
d_q, d_k, d_v, d_gate = _gla_ext.gla_scan_backward(
|
| 143 |
+
grad_out.float().contiguous(),
|
| 144 |
+
q_k.contiguous(),
|
| 145 |
+
k_k.contiguous(),
|
| 146 |
+
v_f.contiguous(),
|
| 147 |
+
chunk_gate.contiguous(),
|
| 148 |
+
states,
|
| 149 |
+
z_norms,
|
| 150 |
+
CS,
|
| 151 |
+
)
|
| 152 |
+
return (d_q, d_k, d_v, d_gate, None)
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
@dataclass
|
| 156 |
+
class CPUGPTConfig:
|
| 157 |
+
vocab_size: int = 50257
|
| 158 |
+
seq_len: int = 1024
|
| 159 |
+
n_layer: int = 12
|
| 160 |
+
n_embd: int = 768
|
| 161 |
+
n_head: int = 12
|
| 162 |
+
fno_modes: int = 256
|
| 163 |
+
gla_chunk: int = 64
|
| 164 |
+
ffn_hidden: int = 2048
|
| 165 |
+
layer_pattern: str = "SSSL"
|
| 166 |
+
bias: bool = False
|
| 167 |
+
dropout: float = 0.0
|
| 168 |
+
fft_dtype: str = "fp32"
|
| 169 |
+
use_flash_fft: bool = False
|
| 170 |
+
gla_delta: bool = False
|
| 171 |
+
sliding_window: int = 0
|
| 172 |
+
swa_window: int = 0
|
| 173 |
+
swa_fused_window: int = 0
|
| 174 |
+
attn_layer_every: int = 0
|
| 175 |
+
attn_full: bool = False
|
| 176 |
+
attn_window: int = 512
|
| 177 |
+
landmark_layer_every: int = 0
|
| 178 |
+
landmark_chunk: int = 32
|
| 179 |
+
landmark_max: int = 64
|
| 180 |
+
gdn_expand_v: float = 1.0
|
| 181 |
+
gdn_head_dim: int = 0
|
| 182 |
+
|
| 183 |
+
def __post_init__(self):
|
| 184 |
+
assert self.n_embd % 16 == 0, (
|
| 185 |
+
f"n_embd={self.n_embd} must be divisible by 16 for AMX BF16"
|
| 186 |
+
)
|
| 187 |
+
assert self.ffn_hidden % 16 == 0, (
|
| 188 |
+
f"ffn_hidden={self.ffn_hidden} must be divisible by 16 for AMX BF16"
|
| 189 |
+
)
|
| 190 |
+
|
| 191 |
+
|
| 192 |
+
def _layer_is_gla(layer_idx: int, n_layer: int, pattern: str) -> bool:
|
| 193 |
+
if pattern == "SSSL":
|
| 194 |
+
return layer_idx % 4 == 3
|
| 195 |
+
elif pattern in ("SGSG", "SLSL"):
|
| 196 |
+
return layer_idx % 2 == 1
|
| 197 |
+
elif pattern == "SSLL":
|
| 198 |
+
return layer_idx % 4 >= 2
|
| 199 |
+
elif pattern == "SLLL":
|
| 200 |
+
return layer_idx % 4 >= 1
|
| 201 |
+
elif pattern == "GLA":
|
| 202 |
+
return True
|
| 203 |
+
elif pattern == "FNO":
|
| 204 |
+
return False
|
| 205 |
+
return False
|
| 206 |
+
|
| 207 |
+
|
| 208 |
+
def rms_norm(x: torch.Tensor) -> torch.Tensor:
|
| 209 |
+
return F.rms_norm(x, (x.size(-1),))
|
| 210 |
+
|
| 211 |
+
|
| 212 |
+
class SwiGLU(nn.Module):
|
| 213 |
+
def __init__(self, cfg: CPUGPTConfig):
|
| 214 |
+
super().__init__()
|
| 215 |
+
h = cfg.ffn_hidden
|
| 216 |
+
d = cfg.n_embd
|
| 217 |
+
self.gate = nn.Linear(d, h, bias=cfg.bias)
|
| 218 |
+
self.up = nn.Linear(d, h, bias=cfg.bias)
|
| 219 |
+
self.down = nn.Linear(h, d, bias=cfg.bias)
|
| 220 |
+
|
| 221 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 222 |
+
return self.down(F.silu(self.gate(x)) * self.up(x))
|
| 223 |
+
|
| 224 |
+
|
| 225 |
+
@torch.compiler.disable
|
| 226 |
+
class _FNOConvFn(torch.autograd.Function):
|
| 227 |
+
@staticmethod
|
| 228 |
+
def forward(ctx, x, filter_td, T):
|
| 229 |
+
x_f = x.float().contiguous()
|
| 230 |
+
f_f = filter_td.float().detach().contiguous()
|
| 231 |
+
y, Xf, Hf = _fno_ext.fno_conv_fwd(x_f, f_f, T)
|
| 232 |
+
ctx.save_for_backward(Xf, Hf)
|
| 233 |
+
ctx.n_use = min(filter_td.shape[1], T)
|
| 234 |
+
ctx.M = filter_td.shape[1]
|
| 235 |
+
return y.to(x.dtype)
|
| 236 |
+
|
| 237 |
+
@staticmethod
|
| 238 |
+
def backward(ctx, grad_out):
|
| 239 |
+
Xf, Hf = ctx.saved_tensors
|
| 240 |
+
d_x, d_filter = _fno_ext.fno_conv_backward(
|
| 241 |
+
grad_out.float().contiguous(), Xf, Hf, ctx.n_use, ctx.M
|
| 242 |
+
)
|
| 243 |
+
return (d_x, d_filter, None)
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
class FNOSeqMixer(nn.Module):
|
| 247 |
+
def __init__(self, cfg: CPUGPTConfig):
|
| 248 |
+
super().__init__()
|
| 249 |
+
C = cfg.n_embd
|
| 250 |
+
M = cfg.fno_modes
|
| 251 |
+
self.filter_td = nn.Parameter(torch.empty(C, M))
|
| 252 |
+
self.out_scale = nn.Linear(C, C, bias=cfg.bias)
|
| 253 |
+
self.register_buffer("_hf_cache", None, persistent=False)
|
| 254 |
+
self._filter_version: int = -1
|
| 255 |
+
self._fft_dtype = _fft_dtype_to_torch(cfg.fft_dtype)
|
| 256 |
+
self._use_flash_fft = cfg.use_flash_fft and _flash_fft_available
|
| 257 |
+
self._flash_fft_conv = None
|
| 258 |
+
self._flash_fft_T: int = -1
|
| 259 |
+
nn.init.normal_(self.filter_td, std=0.02)
|
| 260 |
+
|
| 261 |
+
def _flash_conv(self, x: torch.Tensor, T: int, C: int, n_use: int) -> torch.Tensor:
|
| 262 |
+
if self._flash_fft_conv is None or self._flash_fft_T != T:
|
| 263 |
+
self._flash_fft_conv = _FlashFFTConv(2 * T, dtype=self._fft_dtype).to(
|
| 264 |
+
x.device
|
| 265 |
+
)
|
| 266 |
+
self._flash_fft_T = T
|
| 267 |
+
h = self.filter_td.new_zeros(C, 2 * T)
|
| 268 |
+
h[:, :n_use] = self.filter_td[:, :n_use]
|
| 269 |
+
xp = F.pad(x.transpose(1, 2), (0, T))
|
| 270 |
+
y = self._flash_fft_conv(xp.to(self._fft_dtype), h.to(self._fft_dtype))
|
| 271 |
+
return y[:, :, :T].transpose(1, 2).to(x.dtype)
|
| 272 |
+
|
| 273 |
+
def _rfft_conv(self, x: torch.Tensor, T: int, C: int, n_use: int) -> torch.Tensor:
|
| 274 |
+
dt = self._fft_dtype
|
| 275 |
+
h = self.filter_td.new_zeros(2 * T, C).to(dt)
|
| 276 |
+
h[:n_use] = self.filter_td[:, :n_use].T.to(dt)
|
| 277 |
+
xp = F.pad(x, (0, 0, 0, T)).to(dt)
|
| 278 |
+
Xf = torch.fft.rfft(xp, dim=1)
|
| 279 |
+
Hf = torch.fft.rfft(h, dim=0).unsqueeze(0)
|
| 280 |
+
Xr, Xi = (Xf.real, Xf.imag)
|
| 281 |
+
Hr, Hi = (Hf.real, Hf.imag)
|
| 282 |
+
YHf = torch.view_as_complex(
|
| 283 |
+
torch.stack([Xr * Hr - Xi * Hi, Xr * Hi + Xi * Hr], dim=-1).contiguous()
|
| 284 |
+
)
|
| 285 |
+
return torch.fft.irfft(YHf, n=2 * T, dim=1)[:, :T]
|
| 286 |
+
|
| 287 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 288 |
+
B, T, C = x.shape
|
| 289 |
+
n_use = min(self.filter_td.shape[1], T)
|
| 290 |
+
if _fno_ext is not None:
|
| 291 |
+
y = _FNOConvFn.apply(x, self.filter_td, T)
|
| 292 |
+
elif self._use_flash_fft and x.is_cuda:
|
| 293 |
+
y = self._flash_conv(x, T, C, n_use)
|
| 294 |
+
elif not self.training:
|
| 295 |
+
y = self._forward_eval_cached(x, T, C, n_use)
|
| 296 |
+
else:
|
| 297 |
+
y = self._rfft_conv(x, T, C, n_use)
|
| 298 |
+
return self.out_scale(y.to(x.dtype))
|
| 299 |
+
|
| 300 |
+
@torch.compiler.disable
|
| 301 |
+
def _forward_eval_cached(
|
| 302 |
+
self, x: torch.Tensor, T: int, C: int, n_use: int
|
| 303 |
+
) -> torch.Tensor:
|
| 304 |
+
ver = self.filter_td._version
|
| 305 |
+
if (
|
| 306 |
+
self._hf_cache is None
|
| 307 |
+
or self._filter_version != ver
|
| 308 |
+
or self._hf_cache.shape[0] != T + 1
|
| 309 |
+
):
|
| 310 |
+
h = self.filter_td.new_zeros(2 * T, C)
|
| 311 |
+
h[:n_use] = self.filter_td[:, :n_use].T.detach()
|
| 312 |
+
self._hf_cache = torch.fft.rfft(h.float(), dim=0).contiguous()
|
| 313 |
+
self._filter_version = ver
|
| 314 |
+
dt = self._fft_dtype
|
| 315 |
+
xp = F.pad(x, (0, 0, 0, T)).to(dt)
|
| 316 |
+
Xf = torch.fft.rfft(xp, dim=1)
|
| 317 |
+
H = self._hf_cache.unsqueeze(0)
|
| 318 |
+
Xr, Xi, Hr, Hi = (Xf.real, Xf.imag, H.real, H.imag)
|
| 319 |
+
YHf = torch.view_as_complex(
|
| 320 |
+
torch.stack([Xr * Hr - Xi * Hi, Xr * Hi + Xi * Hr], dim=-1).contiguous()
|
| 321 |
+
)
|
| 322 |
+
return torch.fft.irfft(YHf, n=2 * T, dim=1)[:, :T]
|
| 323 |
+
|
| 324 |
+
def prepare_inference(self):
|
| 325 |
+
if hasattr(self, "_h_td"):
|
| 326 |
+
return
|
| 327 |
+
with torch.no_grad():
|
| 328 |
+
pass
|
| 329 |
+
|
| 330 |
+
def _build_h_td(self, T: int) -> None:
|
| 331 |
+
if hasattr(self, "_h_td"):
|
| 332 |
+
return
|
| 333 |
+
C = self.filter_td.shape[0]
|
| 334 |
+
M = min(self.filter_td.shape[1], T)
|
| 335 |
+
with torch.no_grad():
|
| 336 |
+
h_td = self.filter_td[:, :M].T.float().contiguous()
|
| 337 |
+
self.register_buffer("_h_td", h_td.contiguous())
|
| 338 |
+
|
| 339 |
+
def step(
|
| 340 |
+
self, x: torch.Tensor, buf: torch.Tensor, pos: int
|
| 341 |
+
) -> tuple[torch.Tensor, int]:
|
| 342 |
+
M = buf.shape[1]
|
| 343 |
+
self._build_h_td(M)
|
| 344 |
+
slot = pos % M
|
| 345 |
+
buf[:, slot, :] = x.detach()
|
| 346 |
+
indices = torch.arange(M, device=x.device)
|
| 347 |
+
ordered_idx = (slot + 1 + indices) % M
|
| 348 |
+
ordered = buf[:, ordered_idx, :]
|
| 349 |
+
h_flip = self._h_td.flip(0)
|
| 350 |
+
y = (h_flip.unsqueeze(0) * ordered).sum(1)
|
| 351 |
+
return (self.out_scale(y.to(x.dtype)), pos + 1)
|
| 352 |
+
|
| 353 |
+
def forward_chunk(self, h: torch.Tensor, ctx):
|
| 354 |
+
B, L, C = h.shape
|
| 355 |
+
M = self.filter_td.shape[1]
|
| 356 |
+
if ctx is None:
|
| 357 |
+
ctx = h.new_zeros(B, M - 1, C)
|
| 358 |
+
full = torch.cat([ctx, h], dim=1)
|
| 359 |
+
P = full.shape[1]
|
| 360 |
+
n_use = min(M, P)
|
| 361 |
+
dt = self._fft_dtype
|
| 362 |
+
hk = self.filter_td.new_zeros(2 * P, C).to(dt)
|
| 363 |
+
hk[:n_use] = self.filter_td[:, :n_use].T.to(dt)
|
| 364 |
+
xp = F.pad(full, (0, 0, 0, P)).to(dt)
|
| 365 |
+
Xf = torch.fft.rfft(xp, dim=1)
|
| 366 |
+
Hf = torch.fft.rfft(hk, dim=0).unsqueeze(0)
|
| 367 |
+
Xr, Xi, Hr, Hi = (Xf.real, Xf.imag, Hf.real, Hf.imag)
|
| 368 |
+
YHf = torch.view_as_complex(
|
| 369 |
+
torch.stack([Xr * Hr - Xi * Hi, Xr * Hi + Xi * Hr], dim=-1).contiguous()
|
| 370 |
+
)
|
| 371 |
+
y = torch.fft.irfft(YHf, n=2 * P, dim=1)[:, M - 1 : P]
|
| 372 |
+
return (self.out_scale(y.to(h.dtype)), full[:, -(M - 1) :, :])
|
| 373 |
+
|
| 374 |
+
|
| 375 |
+
class GLAMixer(nn.Module):
|
| 376 |
+
def __init__(self, cfg: CPUGPTConfig):
|
| 377 |
+
super().__init__()
|
| 378 |
+
H = cfg.n_head
|
| 379 |
+
D = cfg.n_embd // H
|
| 380 |
+
C = cfg.n_embd
|
| 381 |
+
CS = cfg.gla_chunk
|
| 382 |
+
assert C % H == 0, "n_embd must be divisible by n_head"
|
| 383 |
+
assert cfg.seq_len % CS == 0, (
|
| 384 |
+
f"seq_len {cfg.seq_len} must be divisible by gla_chunk {CS}"
|
| 385 |
+
)
|
| 386 |
+
self.n_head = H
|
| 387 |
+
self.d_head = D
|
| 388 |
+
self.chunk = CS
|
| 389 |
+
self.gla_delta = bool(getattr(cfg, "gla_delta", False))
|
| 390 |
+
self.sliding_window = int(getattr(cfg, "sliding_window", 0))
|
| 391 |
+
self.swa_window = int(getattr(cfg, "swa_window", 0))
|
| 392 |
+
if self.swa_window > 0:
|
| 393 |
+
self.swa_q = nn.Linear(C, C, bias=False)
|
| 394 |
+
self.swa_k = nn.Linear(C, C, bias=False)
|
| 395 |
+
self.swa_v = nn.Linear(C, C, bias=False)
|
| 396 |
+
self.swa_o = nn.Linear(C, C, bias=False)
|
| 397 |
+
self.swa_fused_window = int(getattr(cfg, "swa_fused_window", 0))
|
| 398 |
+
if self.swa_fused_window > 0:
|
| 399 |
+
self.swa_fused_q = nn.Linear(C, C, bias=False)
|
| 400 |
+
self.swa_fused_k = nn.Linear(C, C, bias=False)
|
| 401 |
+
self.swa_fused_v = nn.Linear(C, C, bias=False)
|
| 402 |
+
self.swa_fused_o = nn.Linear(C, C, bias=False)
|
| 403 |
+
nn.init.zeros_(self.swa_fused_o.weight)
|
| 404 |
+
self.gdn_expand_v = float(getattr(cfg, "gdn_expand_v", 1.0))
|
| 405 |
+
self.gdn_head_dim = int(getattr(cfg, "gdn_head_dim", 0)) or D
|
| 406 |
+
if not (self.gla_delta and _FlaGatedDeltaNet is not None):
|
| 407 |
+
self.q_proj = nn.Linear(C, C, bias=False)
|
| 408 |
+
self.k_proj = nn.Linear(C, C, bias=False)
|
| 409 |
+
self.v_proj = nn.Linear(C, C, bias=False)
|
| 410 |
+
self.g_proj = nn.Linear(C, H, bias=True)
|
| 411 |
+
self.out_proj = nn.Linear(C, C, bias=False)
|
| 412 |
+
self.gla_scale = nn.Parameter(torch.ones(H) * 0.5)
|
| 413 |
+
nn.init.constant_(self.g_proj.bias, -4.0)
|
| 414 |
+
self._swa_mask = None
|
| 415 |
+
if self.gla_delta and _FlaGatedDeltaNet is not None:
|
| 416 |
+
self.gdn = _FlaGatedDeltaNet(
|
| 417 |
+
hidden_size=C,
|
| 418 |
+
num_heads=H,
|
| 419 |
+
head_dim=self.gdn_head_dim,
|
| 420 |
+
expand_v=self.gdn_expand_v,
|
| 421 |
+
mode="chunk",
|
| 422 |
+
)
|
| 423 |
+
|
| 424 |
+
def _python_scan(
|
| 425 |
+
self,
|
| 426 |
+
q_k: torch.Tensor,
|
| 427 |
+
k_k: torch.Tensor,
|
| 428 |
+
v: torch.Tensor,
|
| 429 |
+
chunk_gate: torch.Tensor,
|
| 430 |
+
) -> torch.Tensor:
|
| 431 |
+
B, H, T, D = q_k.shape
|
| 432 |
+
CS = self.chunk
|
| 433 |
+
n_chunks = T // CS
|
| 434 |
+
q_c = q_k.view(B, H, n_chunks, CS, D)
|
| 435 |
+
k_c = k_k.view(B, H, n_chunks, CS, D)
|
| 436 |
+
v_c = v.view(B, H, n_chunks, CS, D)
|
| 437 |
+
state = torch.zeros(B, H, D, D, device=q_k.device, dtype=q_k.dtype)
|
| 438 |
+
z_norm = torch.zeros(B, H, D, device=q_k.device, dtype=q_k.dtype)
|
| 439 |
+
out = torch.zeros(B, H, T, D, device=q_k.device, dtype=q_k.dtype)
|
| 440 |
+
for c in range(n_chunks):
|
| 441 |
+
num = q_c[:, :, c] @ state
|
| 442 |
+
den = (q_c[:, :, c] @ z_norm.unsqueeze(-1)).clamp(min=1.0)
|
| 443 |
+
out[:, :, c * CS : (c + 1) * CS] = num / den
|
| 444 |
+
g = chunk_gate[:, :, c, None, None]
|
| 445 |
+
state = g * state + k_c[:, :, c].transpose(-2, -1) @ v_c[:, :, c]
|
| 446 |
+
z_norm = chunk_gate[:, :, c, None] * z_norm + k_c[:, :, c].sum(dim=-2)
|
| 447 |
+
return out
|
| 448 |
+
|
| 449 |
+
def _swa(self, q, k, v):
|
| 450 |
+
B, H, T, D = q.shape
|
| 451 |
+
w = self.sliding_window
|
| 452 |
+
pad = (w - T % w) % w
|
| 453 |
+
if pad:
|
| 454 |
+
q, k, v = (F.pad(t, (0, 0, 0, pad)) for t in (q, k, v))
|
| 455 |
+
Tp = T + pad
|
| 456 |
+
nb = Tp // w
|
| 457 |
+
qb = q.reshape(B, H, nb, w, D)
|
| 458 |
+
kb = k.reshape(B, H, nb, w, D)
|
| 459 |
+
vb = v.reshape(B, H, nb, w, D)
|
| 460 |
+
kc = torch.cat([F.pad(kb, (0, 0, 0, 0, 1, 0))[:, :, :-1], kb], dim=3)
|
| 461 |
+
vc = torch.cat([F.pad(vb, (0, 0, 0, 0, 1, 0))[:, :, :-1], vb], dim=3)
|
| 462 |
+
if (
|
| 463 |
+
self._swa_mask is None
|
| 464 |
+
or self._swa_mask.shape[-1] != 2 * w
|
| 465 |
+
or self._swa_mask.device != q.device
|
| 466 |
+
):
|
| 467 |
+
i = torch.arange(w, device=q.device)
|
| 468 |
+
j = torch.arange(2 * w, device=q.device)
|
| 469 |
+
self._swa_mask = (j[None, :] < w) | (j[None, :] - w <= i[:, None])
|
| 470 |
+
out = F.scaled_dot_product_attention(qb, kc, vc, attn_mask=self._swa_mask)
|
| 471 |
+
return out.reshape(B, H, Tp, D)[:, :, :T]
|
| 472 |
+
|
| 473 |
+
def _swa_exact(self, x: torch.Tensor) -> torch.Tensor:
|
| 474 |
+
B, T, C = x.shape
|
| 475 |
+
H, D, w = (self.n_head, self.d_head, self.swa_window)
|
| 476 |
+
q = self.swa_q(x).reshape(B, T, H, D).transpose(1, 2)
|
| 477 |
+
k = self.swa_k(x).reshape(B, T, H, D).transpose(1, 2)
|
| 478 |
+
v = self.swa_v(x).reshape(B, T, H, D).transpose(1, 2)
|
| 479 |
+
i = torch.arange(T, device=x.device)[:, None]
|
| 480 |
+
j = torch.arange(T, device=x.device)[None, :]
|
| 481 |
+
mask = (j <= i) & (j > i - w)
|
| 482 |
+
o = F.scaled_dot_product_attention(q, k, v, attn_mask=mask)
|
| 483 |
+
o = o.transpose(1, 2).reshape(B, T, C)
|
| 484 |
+
return self.swa_o(o)
|
| 485 |
+
|
| 486 |
+
def _swa_fused(self, x: torch.Tensor) -> torch.Tensor:
|
| 487 |
+
B, T, C = x.shape
|
| 488 |
+
H, D, w = (self.n_head, self.d_head, self.swa_fused_window)
|
| 489 |
+
q = self.swa_fused_q(x).reshape(B, T, H, D).transpose(1, 2)
|
| 490 |
+
k = self.swa_fused_k(x).reshape(B, T, H, D).transpose(1, 2)
|
| 491 |
+
v = self.swa_fused_v(x).reshape(B, T, H, D).transpose(1, 2)
|
| 492 |
+
i = torch.arange(T, device=x.device)[:, None]
|
| 493 |
+
j = torch.arange(T, device=x.device)[None, :]
|
| 494 |
+
mask = (j <= i) & (j > i - w)
|
| 495 |
+
o = F.scaled_dot_product_attention(q, k, v, attn_mask=mask)
|
| 496 |
+
o = o.transpose(1, 2).reshape(B, T, C)
|
| 497 |
+
return x + self.swa_fused_o(o)
|
| 498 |
+
|
| 499 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 500 |
+
B, T, C = x.shape
|
| 501 |
+
H, D, CS = (self.n_head, self.d_head, self.chunk)
|
| 502 |
+
if self.gla_delta and hasattr(self, "gdn") and x.is_cuda:
|
| 503 |
+
gdn_in = self._swa_fused(x) if self.swa_fused_window > 0 else x
|
| 504 |
+
o = self.gdn(gdn_in)
|
| 505 |
+
o = o[0] if isinstance(o, tuple) else o
|
| 506 |
+
if self.swa_window > 0:
|
| 507 |
+
o = o + self._swa_exact(x)
|
| 508 |
+
return o
|
| 509 |
+
q = self.q_proj(x).reshape(B, T, H, D).transpose(1, 2)
|
| 510 |
+
k = self.k_proj(x).reshape(B, T, H, D).transpose(1, 2)
|
| 511 |
+
v = self.v_proj(x).reshape(B, T, H, D).transpose(1, 2)
|
| 512 |
+
if x.is_cuda and _fla_available:
|
| 513 |
+
log_g = -F.softplus(self.g_proj(x))
|
| 514 |
+
q_t = q.transpose(1, 2).contiguous()
|
| 515 |
+
k_t = k.transpose(1, 2).contiguous()
|
| 516 |
+
v_t = v.transpose(1, 2).contiguous()
|
| 517 |
+
if self.gla_delta and _fla_chunk_gdr is not None:
|
| 518 |
+
beta = self.beta_proj(x).float()
|
| 519 |
+
g_delta = self.a_proj(x).float()
|
| 520 |
+
y_fla, _ = _fla_chunk_gdr(
|
| 521 |
+
q_t,
|
| 522 |
+
k_t,
|
| 523 |
+
v_t,
|
| 524 |
+
g=g_delta,
|
| 525 |
+
beta=beta,
|
| 526 |
+
scale=D ** (-0.5),
|
| 527 |
+
output_final_state=False,
|
| 528 |
+
use_beta_sigmoid_in_kernel=True,
|
| 529 |
+
use_qk_l2norm_in_kernel=True,
|
| 530 |
+
)
|
| 531 |
+
else:
|
| 532 |
+
g_t = log_g.unsqueeze(-1).expand(B, T, H, D).contiguous().float()
|
| 533 |
+
y_fla, _ = _fla_chunk_gla(
|
| 534 |
+
q_t, k_t, v_t, g=g_t, scale=D ** (-0.5), output_final_state=False
|
| 535 |
+
)
|
| 536 |
+
y = y_fla.to(x.dtype).transpose(1, 2).reshape(B, T, C)
|
| 537 |
+
if self.sliding_window > 0:
|
| 538 |
+
y = y + self._swa(q, k, v).transpose(1, 2).reshape(B, T, C)
|
| 539 |
+
return self.out_proj(y)
|
| 540 |
+
n_chunks = T // CS
|
| 541 |
+
BH = B * H
|
| 542 |
+
q_l = q.reshape(BH, n_chunks, CS, D)
|
| 543 |
+
k_l = k.reshape(BH, n_chunks, CS, D)
|
| 544 |
+
v_l = v.reshape(BH, n_chunks, CS, D)
|
| 545 |
+
y_local = F.scaled_dot_product_attention(q_l, k_l, v_l, is_causal=True).reshape(
|
| 546 |
+
B, H, T, D
|
| 547 |
+
)
|
| 548 |
+
if _CPU_HAS_BF16 and q.dtype == torch.bfloat16:
|
| 549 |
+
q_k = F.elu(q) + 1.0
|
| 550 |
+
k_k = F.elu(k) + 1.0
|
| 551 |
+
v_f = v
|
| 552 |
+
else:
|
| 553 |
+
q_k = F.elu(q.float()) + 1.0
|
| 554 |
+
k_k = F.elu(k.float()) + 1.0
|
| 555 |
+
v_f = v.float()
|
| 556 |
+
log_g = -F.softplus(self.g_proj(x).float())
|
| 557 |
+
log_g = log_g.transpose(1, 2)
|
| 558 |
+
chunk_log_g = log_g.reshape(B, H, n_chunks, CS).sum(-1)
|
| 559 |
+
chunk_gate = chunk_log_g.exp()
|
| 560 |
+
if _gla_ext is not None and q_k.dtype == torch.float32 and (not q_k.is_cuda):
|
| 561 |
+
y_gla = _GLAScanFn.apply(q_k, k_k, v_f, chunk_gate, CS)
|
| 562 |
+
else:
|
| 563 |
+
y_gla = _gla_scan_py(q_k, k_k, v_f, chunk_gate, CS)
|
| 564 |
+
scale = self.gla_scale.reshape(1, H, 1, 1).to(x.dtype)
|
| 565 |
+
y = (y_local + scale * y_gla.to(x.dtype)).transpose(1, 2).reshape(B, T, C)
|
| 566 |
+
return self.out_proj(y)
|
| 567 |
+
|
| 568 |
+
def step(
|
| 569 |
+
self, x: torch.Tensor, state: torch.Tensor, z_norm: torch.Tensor
|
| 570 |
+
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
|
| 571 |
+
B = x.shape[0]
|
| 572 |
+
H, D = (self.n_head, self.d_head)
|
| 573 |
+
q = self.q_proj(x).view(B, H, D)
|
| 574 |
+
k = self.k_proj(x).view(B, H, D)
|
| 575 |
+
v = self.v_proj(x).view(B, H, D)
|
| 576 |
+
log_g = -F.softplus(self.g_proj(x).float())
|
| 577 |
+
scale = D ** (-0.5)
|
| 578 |
+
if x.is_cuda and _fla_available:
|
| 579 |
+
st = (
|
| 580 |
+
state
|
| 581 |
+
if torch.is_tensor(state) and state.dtype == torch.float32
|
| 582 |
+
else None
|
| 583 |
+
)
|
| 584 |
+
g_t = log_g.view(B, 1, H, 1).expand(B, 1, H, D).contiguous()
|
| 585 |
+
y, state = _fla_chunk_gla(
|
| 586 |
+
q.view(B, 1, H, D),
|
| 587 |
+
k.view(B, 1, H, D),
|
| 588 |
+
v.view(B, 1, H, D),
|
| 589 |
+
g=g_t,
|
| 590 |
+
scale=scale,
|
| 591 |
+
initial_state=st,
|
| 592 |
+
output_final_state=True,
|
| 593 |
+
)
|
| 594 |
+
y = y.reshape(B, H * D).to(x.dtype)
|
| 595 |
+
return (self.out_proj(y), state, z_norm)
|
| 596 |
+
gate = log_g.exp()
|
| 597 |
+
qf, kf, vf = (q.float(), k.float(), v.float())
|
| 598 |
+
if not (torch.is_tensor(state) and state.dim() == 4):
|
| 599 |
+
state = torch.zeros(B, H, D, D, device=x.device, dtype=torch.float32)
|
| 600 |
+
state = gate.unsqueeze(-1).unsqueeze(-1) * state + torch.einsum(
|
| 601 |
+
"bhd,bhe->bhde", kf, vf
|
| 602 |
+
)
|
| 603 |
+
y_gla = torch.einsum("bhd,bhde->bhe", qf, state) * scale
|
| 604 |
+
return (self.out_proj(y_gla.reshape(B, H * D).to(x.dtype)), state, z_norm)
|
| 605 |
+
|
| 606 |
+
def forward_chunk(self, h: torch.Tensor, state):
|
| 607 |
+
B, L, C = h.shape
|
| 608 |
+
H, D = (self.n_head, self.d_head)
|
| 609 |
+
q = self.q_proj(h).view(B, L, H, D)
|
| 610 |
+
k = self.k_proj(h).view(B, L, H, D)
|
| 611 |
+
v = self.v_proj(h).view(B, L, H, D)
|
| 612 |
+
log_g = -F.softplus(self.g_proj(h).float())
|
| 613 |
+
g = log_g.unsqueeze(-1).expand(B, L, H, D).contiguous()
|
| 614 |
+
st = state if torch.is_tensor(state) and state.dtype == torch.float32 else None
|
| 615 |
+
y, state = _fla_chunk_gla(
|
| 616 |
+
q, k, v, g=g, scale=D ** (-0.5), initial_state=st, output_final_state=True
|
| 617 |
+
)
|
| 618 |
+
return (self.out_proj(y.reshape(B, L, C).to(h.dtype)), state)
|
| 619 |
+
|
| 620 |
+
|
| 621 |
+
class AttnMixer(nn.Module):
|
| 622 |
+
def __init__(self, cfg: CPUGPTConfig):
|
| 623 |
+
super().__init__()
|
| 624 |
+
C, H = (cfg.n_embd, cfg.n_head)
|
| 625 |
+
assert C % H == 0
|
| 626 |
+
self.n_head = H
|
| 627 |
+
self.d_head = C // H
|
| 628 |
+
self.full = bool(getattr(cfg, "attn_full", False))
|
| 629 |
+
self.window = int(getattr(cfg, "attn_window", 512))
|
| 630 |
+
self.q_proj = nn.Linear(C, C, bias=False)
|
| 631 |
+
self.k_proj = nn.Linear(C, C, bias=False)
|
| 632 |
+
self.v_proj = nn.Linear(C, C, bias=False)
|
| 633 |
+
self.o_proj = nn.Linear(C, C, bias=False)
|
| 634 |
+
|
| 635 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 636 |
+
B, T, C = x.shape
|
| 637 |
+
H, D = (self.n_head, self.d_head)
|
| 638 |
+
q = self.q_proj(x).reshape(B, T, H, D).transpose(1, 2)
|
| 639 |
+
k = self.k_proj(x).reshape(B, T, H, D).transpose(1, 2)
|
| 640 |
+
v = self.v_proj(x).reshape(B, T, H, D).transpose(1, 2)
|
| 641 |
+
if self.full:
|
| 642 |
+
o = F.scaled_dot_product_attention(q, k, v, is_causal=True)
|
| 643 |
+
else:
|
| 644 |
+
w = self.window
|
| 645 |
+
i = torch.arange(T, device=x.device)[:, None]
|
| 646 |
+
j = torch.arange(T, device=x.device)[None, :]
|
| 647 |
+
mask = (j <= i) & (j > i - w)
|
| 648 |
+
o = F.scaled_dot_product_attention(q, k, v, attn_mask=mask)
|
| 649 |
+
o = o.transpose(1, 2).reshape(B, T, C)
|
| 650 |
+
return self.o_proj(o)
|
| 651 |
+
|
| 652 |
+
|
| 653 |
+
def _layer_is_attn(layer_idx: int, cfg: CPUGPTConfig) -> bool:
|
| 654 |
+
k = int(getattr(cfg, "attn_layer_every", 0))
|
| 655 |
+
if k <= 0:
|
| 656 |
+
return False
|
| 657 |
+
return (layer_idx + 1) % k == 0
|
| 658 |
+
|
| 659 |
+
|
| 660 |
+
class LandmarkMixer(nn.Module):
|
| 661 |
+
def __init__(self, cfg: CPUGPTConfig):
|
| 662 |
+
super().__init__()
|
| 663 |
+
C, H = (cfg.n_embd, cfg.n_head)
|
| 664 |
+
assert C % H == 0
|
| 665 |
+
self.n_head = H
|
| 666 |
+
self.d_head = C // H
|
| 667 |
+
self.chunk = max(1, int(getattr(cfg, "landmark_chunk", 32)))
|
| 668 |
+
self.max_land = max(1, int(getattr(cfg, "landmark_max", 64)))
|
| 669 |
+
self.q_proj = nn.Linear(C, C, bias=False)
|
| 670 |
+
self.k_proj = nn.Linear(C, C, bias=False)
|
| 671 |
+
self.v_proj = nn.Linear(C, C, bias=False)
|
| 672 |
+
self.o_proj = nn.Linear(C, C, bias=False)
|
| 673 |
+
self.sink = nn.Parameter(torch.zeros(1, 1, C))
|
| 674 |
+
|
| 675 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 676 |
+
B, T, C = x.shape
|
| 677 |
+
H, D = (self.n_head, self.d_head)
|
| 678 |
+
c = max(self.chunk, (T + self.max_land - 1) // self.max_land)
|
| 679 |
+
nc = (T + c - 1) // c
|
| 680 |
+
pad = nc * c - T
|
| 681 |
+
xp = F.pad(x, (0, 0, 0, pad))
|
| 682 |
+
land = xp.view(B, nc, c, C).mean(2)
|
| 683 |
+
land = torch.cat([self.sink.expand(B, 1, C), land], dim=1)
|
| 684 |
+
q = self.q_proj(x).reshape(B, T, H, D).transpose(1, 2)
|
| 685 |
+
k = self.k_proj(land).reshape(B, nc + 1, H, D).transpose(1, 2)
|
| 686 |
+
v = self.v_proj(land).reshape(B, nc + 1, H, D).transpose(1, 2)
|
| 687 |
+
tok_c = (torch.arange(T, device=x.device) // c)[:, None]
|
| 688 |
+
land_i = torch.arange(nc, device=x.device)[None, :]
|
| 689 |
+
sink_ok = torch.ones(T, 1, dtype=torch.bool, device=x.device)
|
| 690 |
+
chunk_ok = land_i < tok_c
|
| 691 |
+
mask = torch.cat([sink_ok, chunk_ok], dim=1).view(1, 1, T, nc + 1)
|
| 692 |
+
o = F.scaled_dot_product_attention(q, k, v, attn_mask=mask)
|
| 693 |
+
o = o.transpose(1, 2).reshape(B, T, C)
|
| 694 |
+
return self.o_proj(o)
|
| 695 |
+
|
| 696 |
+
|
| 697 |
+
def _layer_is_landmark(layer_idx: int, cfg: CPUGPTConfig) -> bool:
|
| 698 |
+
k = int(getattr(cfg, "landmark_layer_every", 0))
|
| 699 |
+
return k > 0 and (layer_idx + 1) % k == 0
|
| 700 |
+
|
| 701 |
+
|
| 702 |
+
class CPUGPTBlock(nn.Module):
|
| 703 |
+
def __init__(self, cfg: CPUGPTConfig, layer_idx: int):
|
| 704 |
+
super().__init__()
|
| 705 |
+
is_landmark = _layer_is_landmark(layer_idx, cfg)
|
| 706 |
+
is_attn = not is_landmark and _layer_is_attn(layer_idx, cfg)
|
| 707 |
+
is_gla = (
|
| 708 |
+
not is_landmark
|
| 709 |
+
and (not is_attn)
|
| 710 |
+
and _layer_is_gla(layer_idx, cfg.n_layer, cfg.layer_pattern)
|
| 711 |
+
)
|
| 712 |
+
if is_landmark:
|
| 713 |
+
self.mixer = LandmarkMixer(cfg)
|
| 714 |
+
elif is_attn:
|
| 715 |
+
self.mixer = AttnMixer(cfg)
|
| 716 |
+
else:
|
| 717 |
+
self.mixer = GLAMixer(cfg) if is_gla else FNOSeqMixer(cfg)
|
| 718 |
+
self.ffn = SwiGLU(cfg)
|
| 719 |
+
self.ln1 = nn.RMSNorm(cfg.n_embd)
|
| 720 |
+
self.ln2 = nn.RMSNorm(cfg.n_embd)
|
| 721 |
+
self.is_gla = is_gla
|
| 722 |
+
self.is_attn = is_attn
|
| 723 |
+
self.is_landmark = is_landmark
|
| 724 |
+
|
| 725 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 726 |
+
x = x + self.mixer(self.ln1(x))
|
| 727 |
+
x = x + self.ffn(self.ln2(x))
|
| 728 |
+
return x
|
| 729 |
+
|
| 730 |
+
def step(self, x: torch.Tensor, bstate: dict) -> tuple:
|
| 731 |
+
h = self.ln1(x)
|
| 732 |
+
mixer = self.mixer
|
| 733 |
+
if isinstance(mixer, (AttnMixer, LandmarkMixer)):
|
| 734 |
+
raise NotImplementedError(
|
| 735 |
+
"AttnMixer/LandmarkMixer recurrent step() not implemented; use forward()"
|
| 736 |
+
)
|
| 737 |
+
if isinstance(mixer, GLAMixer):
|
| 738 |
+
h_out, bstate["gla_state"], bstate["z_norm"] = mixer.step(
|
| 739 |
+
h, bstate["gla_state"], bstate["z_norm"]
|
| 740 |
+
)
|
| 741 |
+
else:
|
| 742 |
+
assert isinstance(mixer, FNOSeqMixer)
|
| 743 |
+
h_out, bstate["pos"] = mixer.step(h, bstate["buf"], bstate["pos"])
|
| 744 |
+
x = x + h_out
|
| 745 |
+
x = x + self.ffn(self.ln2(x))
|
| 746 |
+
return (x, bstate)
|
| 747 |
+
|
| 748 |
+
def forward_chunk(self, x: torch.Tensor, bstate: dict) -> tuple:
|
| 749 |
+
h = self.ln1(x)
|
| 750 |
+
mixer = self.mixer
|
| 751 |
+
if isinstance(mixer, (AttnMixer, LandmarkMixer)):
|
| 752 |
+
raise NotImplementedError(
|
| 753 |
+
"AttnMixer/LandmarkMixer forward_chunk() not implemented; use forward()"
|
| 754 |
+
)
|
| 755 |
+
if isinstance(mixer, GLAMixer):
|
| 756 |
+
h_out, bstate["gla_state"] = mixer.forward_chunk(h, bstate.get("gla_state"))
|
| 757 |
+
else:
|
| 758 |
+
assert isinstance(mixer, FNOSeqMixer)
|
| 759 |
+
h_out, bstate["fno_ctx"] = mixer.forward_chunk(h, bstate.get("fno_ctx"))
|
| 760 |
+
x = x + h_out
|
| 761 |
+
x = x + self.ffn(self.ln2(x))
|
| 762 |
+
return (x, bstate)
|
| 763 |
+
|
| 764 |
+
|
| 765 |
+
class _ChunkedCEFn(torch.autograd.Function):
|
| 766 |
+
@staticmethod
|
| 767 |
+
def forward(ctx, x_flat, weight, targets, chunk_size):
|
| 768 |
+
N = x_flat.shape[0]
|
| 769 |
+
use_bf16 = x_flat.dtype == torch.bfloat16
|
| 770 |
+
count = (targets != -1).sum().clamp(min=1)
|
| 771 |
+
w_g = weight.bfloat16() if use_bf16 else weight.float()
|
| 772 |
+
loss_sum = torch.zeros((), dtype=torch.float32, device=x_flat.device)
|
| 773 |
+
for start in range(0, N, chunk_size):
|
| 774 |
+
end = min(start + chunk_size, N)
|
| 775 |
+
x_c = x_flat[start:end]
|
| 776 |
+
t_c = targets[start:end]
|
| 777 |
+
logits_c = (x_c @ w_g.T).float()
|
| 778 |
+
logits_c = 15.0 * torch.tanh(logits_c * (1.0 / 15.0))
|
| 779 |
+
loss_sum = loss_sum + F.cross_entropy(
|
| 780 |
+
logits_c, t_c, ignore_index=-1, reduction="sum"
|
| 781 |
+
)
|
| 782 |
+
ctx.save_for_backward(x_flat, weight, targets)
|
| 783 |
+
ctx.chunk_size = chunk_size
|
| 784 |
+
ctx.count = int(count.item())
|
| 785 |
+
ctx.use_bf16 = use_bf16
|
| 786 |
+
return loss_sum / count
|
| 787 |
+
|
| 788 |
+
@staticmethod
|
| 789 |
+
def backward(ctx, grad_out):
|
| 790 |
+
x_flat, weight, targets = ctx.saved_tensors
|
| 791 |
+
N, C = x_flat.shape
|
| 792 |
+
chunk_size = ctx.chunk_size
|
| 793 |
+
use_bf16 = ctx.use_bf16
|
| 794 |
+
scale = grad_out.item() / ctx.count
|
| 795 |
+
w_g = weight.bfloat16() if use_bf16 else weight.float()
|
| 796 |
+
dx = torch.zeros(N, C, dtype=torch.float32, device=x_flat.device)
|
| 797 |
+
dw = torch.zeros_like(weight, dtype=torch.float32)
|
| 798 |
+
for start in range(0, N, chunk_size):
|
| 799 |
+
end = min(start + chunk_size, N)
|
| 800 |
+
x_c = x_flat[start:end]
|
| 801 |
+
t_c = targets[start:end]
|
| 802 |
+
logits_c = (x_c @ w_g.T).float()
|
| 803 |
+
tanh_c = torch.tanh(logits_c * (1.0 / 15.0))
|
| 804 |
+
logits_cap = 15.0 * tanh_c
|
| 805 |
+
probs_c = torch.softmax(logits_cap, dim=-1)
|
| 806 |
+
valid = t_c != -1
|
| 807 |
+
probs_c[~valid] = 0.0
|
| 808 |
+
if valid.any():
|
| 809 |
+
probs_c[valid, t_c[valid]] -= 1.0
|
| 810 |
+
d_logits_c = probs_c * (1.0 - tanh_c * tanh_c) * scale
|
| 811 |
+
if use_bf16:
|
| 812 |
+
dx[start:end] = (d_logits_c.bfloat16() @ w_g).float()
|
| 813 |
+
else:
|
| 814 |
+
dx[start:end] = d_logits_c @ w_g
|
| 815 |
+
if use_bf16:
|
| 816 |
+
dw.add_((d_logits_c.bfloat16().T @ x_c).float())
|
| 817 |
+
else:
|
| 818 |
+
dw.addmm_(d_logits_c.T, x_c)
|
| 819 |
+
return (dx.to(x_flat.dtype), dw, None, None)
|
| 820 |
+
|
| 821 |
+
|
| 822 |
+
def _chunked_cross_entropy(
|
| 823 |
+
weight: torch.Tensor, x: torch.Tensor, targets: torch.Tensor, chunk: int = 512
|
| 824 |
+
) -> torch.Tensor:
|
| 825 |
+
B, T, C = x.shape
|
| 826 |
+
return _ChunkedCEFn.apply(
|
| 827 |
+
x.reshape(B * T, C), weight, targets.reshape(B * T), chunk
|
| 828 |
+
)
|
| 829 |
+
|
| 830 |
+
|
| 831 |
+
class CPUGPT(nn.Module):
|
| 832 |
+
def __init__(self, cfg: CPUGPTConfig):
|
| 833 |
+
super().__init__()
|
| 834 |
+
self.cfg = cfg
|
| 835 |
+
self.wte = nn.Embedding(cfg.vocab_size, cfg.n_embd)
|
| 836 |
+
self.blocks = nn.ModuleList([CPUGPTBlock(cfg, i) for i in range(cfg.n_layer)])
|
| 837 |
+
self.ln_out = nn.RMSNorm(cfg.n_embd)
|
| 838 |
+
self.lm_head = nn.Linear(cfg.n_embd, cfg.vocab_size, bias=False)
|
| 839 |
+
self.lm_head.weight = self.wte.weight
|
| 840 |
+
self._init_weights()
|
| 841 |
+
|
| 842 |
+
def _init_weights(self):
|
| 843 |
+
nn.init.normal_(self.wte.weight, std=0.02)
|
| 844 |
+
for block in self.blocks:
|
| 845 |
+
if isinstance(block.mixer, GLAMixer) and hasattr(block.mixer, "q_proj"):
|
| 846 |
+
for proj in [
|
| 847 |
+
block.mixer.q_proj,
|
| 848 |
+
block.mixer.k_proj,
|
| 849 |
+
block.mixer.v_proj,
|
| 850 |
+
block.mixer.out_proj,
|
| 851 |
+
]:
|
| 852 |
+
nn.init.normal_(proj.weight, std=0.02)
|
| 853 |
+
if isinstance(block.mixer, AttnMixer):
|
| 854 |
+
for proj in [
|
| 855 |
+
block.mixer.q_proj,
|
| 856 |
+
block.mixer.k_proj,
|
| 857 |
+
block.mixer.v_proj,
|
| 858 |
+
block.mixer.o_proj,
|
| 859 |
+
]:
|
| 860 |
+
nn.init.normal_(proj.weight, std=0.02)
|
| 861 |
+
nn.init.normal_(block.ffn.gate.weight, std=0.02)
|
| 862 |
+
nn.init.normal_(block.ffn.up.weight, std=0.02)
|
| 863 |
+
nn.init.zeros_(block.ffn.down.weight)
|
| 864 |
+
|
| 865 |
+
def param_count(self) -> int:
|
| 866 |
+
return sum((p.numel() for p in self.parameters()))
|
| 867 |
+
|
| 868 |
+
def prepare_inference(self):
|
| 869 |
+
for block in self.blocks:
|
| 870 |
+
if not block.is_gla and (not getattr(block, "is_attn", False)):
|
| 871 |
+
block.mixer.prepare_inference()
|
| 872 |
+
|
| 873 |
+
def init_state(self, batch_size: int = 1, device=None) -> list:
|
| 874 |
+
if device is None:
|
| 875 |
+
device = next(self.parameters()).device
|
| 876 |
+
H = self.cfg.n_head
|
| 877 |
+
D = self.cfg.n_embd // H
|
| 878 |
+
M = self.cfg.fno_modes
|
| 879 |
+
C = self.cfg.n_embd
|
| 880 |
+
states = []
|
| 881 |
+
for block in self.blocks:
|
| 882 |
+
if getattr(block, "is_attn", False):
|
| 883 |
+
states.append({})
|
| 884 |
+
elif block.is_gla:
|
| 885 |
+
states.append(
|
| 886 |
+
{
|
| 887 |
+
"gla_state": torch.zeros(batch_size, H, D, D, device=device),
|
| 888 |
+
"z_norm": torch.zeros(batch_size, H, D, device=device),
|
| 889 |
+
}
|
| 890 |
+
)
|
| 891 |
+
else:
|
| 892 |
+
states.append(
|
| 893 |
+
{"buf": torch.zeros(batch_size, M, C, device=device), "pos": 0}
|
| 894 |
+
)
|
| 895 |
+
return states
|
| 896 |
+
|
| 897 |
+
@torch.no_grad()
|
| 898 |
+
def step(self, idx: torch.Tensor, states: list):
|
| 899 |
+
x = self.wte(idx.unsqueeze(1) if idx.dim() == 1 else idx)
|
| 900 |
+
if x.dim() == 3:
|
| 901 |
+
x = x.squeeze(1)
|
| 902 |
+
x = F.rms_norm(x, (x.size(-1),))
|
| 903 |
+
new_states = []
|
| 904 |
+
for block, bstate in zip(self.blocks, states):
|
| 905 |
+
x, bstate = block.step(x, bstate)
|
| 906 |
+
new_states.append(bstate)
|
| 907 |
+
x = self.ln_out(x)
|
| 908 |
+
logits = self.lm_head(x.unsqueeze(1)).squeeze(1).float()
|
| 909 |
+
logits = 15.0 * torch.tanh(logits / 15.0)
|
| 910 |
+
return (logits, new_states)
|
| 911 |
+
|
| 912 |
+
@torch.no_grad()
|
| 913 |
+
def prefill_chunked(self, idx: torch.Tensor, chunk_size: int = 512):
|
| 914 |
+
B, T = idx.shape
|
| 915 |
+
states = [dict() for _ in self.blocks]
|
| 916 |
+
last_hidden = None
|
| 917 |
+
for c0 in range(0, T, chunk_size):
|
| 918 |
+
x = self.wte(idx[:, c0 : c0 + chunk_size])
|
| 919 |
+
x = F.rms_norm(x, (x.size(-1),))
|
| 920 |
+
for l, block in enumerate(self.blocks):
|
| 921 |
+
x, states[l] = block.forward_chunk(x, states[l])
|
| 922 |
+
last_hidden = x[:, -1:, :]
|
| 923 |
+
logits = self.lm_head(self.ln_out(last_hidden)).float()
|
| 924 |
+
logits = 15.0 * torch.tanh(logits / 15.0)
|
| 925 |
+
return (logits.squeeze(1), states)
|
| 926 |
+
|
| 927 |
+
@torch.no_grad()
|
| 928 |
+
def generate(
|
| 929 |
+
self,
|
| 930 |
+
prompt_ids: torch.Tensor,
|
| 931 |
+
max_new_tokens: int = 200,
|
| 932 |
+
temperature: float = 0.8,
|
| 933 |
+
top_k: int = 50,
|
| 934 |
+
) -> torch.Tensor:
|
| 935 |
+
self.prepare_inference()
|
| 936 |
+
device = prompt_ids.device
|
| 937 |
+
states = self.init_state(batch_size=1, device=device)
|
| 938 |
+
logits = torch.zeros(prompt_ids.shape[0], self.cfg.vocab_size, device=device)
|
| 939 |
+
for i in range(prompt_ids.shape[1]):
|
| 940 |
+
tok = prompt_ids[:, i]
|
| 941 |
+
logits, states = self.step(tok, states)
|
| 942 |
+
generated = []
|
| 943 |
+
for _ in range(max_new_tokens):
|
| 944 |
+
if temperature == 0.0:
|
| 945 |
+
next_tok = logits.argmax(dim=-1)
|
| 946 |
+
else:
|
| 947 |
+
scaled = logits / temperature
|
| 948 |
+
if top_k > 0:
|
| 949 |
+
topk_vals, _ = torch.topk(scaled, top_k)
|
| 950 |
+
scaled = scaled.masked_fill(
|
| 951 |
+
scaled < topk_vals[:, -1:], float("-inf")
|
| 952 |
+
)
|
| 953 |
+
probs = torch.softmax(scaled, dim=-1)
|
| 954 |
+
next_tok = torch.multinomial(probs, num_samples=1).squeeze(1)
|
| 955 |
+
generated.append(next_tok)
|
| 956 |
+
logits, states = self.step(next_tok, states)
|
| 957 |
+
return torch.stack(generated, dim=1)
|
| 958 |
+
|
| 959 |
+
def forward(
|
| 960 |
+
self,
|
| 961 |
+
idx: torch.Tensor,
|
| 962 |
+
targets: Optional[torch.Tensor] = None,
|
| 963 |
+
reduction: str = "mean",
|
| 964 |
+
) -> torch.Tensor:
|
| 965 |
+
B, T = idx.shape
|
| 966 |
+
assert T <= self.cfg.seq_len, f"Sequence {T} > max {self.cfg.seq_len}"
|
| 967 |
+
x = self.wte(idx)
|
| 968 |
+
x = F.rms_norm(x, (x.size(-1),))
|
| 969 |
+
if _CPU_HAS_BF16:
|
| 970 |
+
with torch.autocast(device_type="cpu", dtype=torch.bfloat16):
|
| 971 |
+
for block in self.blocks:
|
| 972 |
+
x = block(x)
|
| 973 |
+
else:
|
| 974 |
+
for block in self.blocks:
|
| 975 |
+
x = block(x)
|
| 976 |
+
x = self.ln_out(x)
|
| 977 |
+
if targets is None:
|
| 978 |
+
logits = self.lm_head(x).float()
|
| 979 |
+
logits = 15.0 * torch.tanh(logits / 15.0)
|
| 980 |
+
return logits
|
| 981 |
+
return _chunked_cross_entropy(self.lm_head.weight, x, targets)
|
| 982 |
+
|
| 983 |
+
|
| 984 |
+
def gpt2_small_config(**overrides) -> CPUGPTConfig:
|
| 985 |
+
cfg = CPUGPTConfig(
|
| 986 |
+
vocab_size=50257,
|
| 987 |
+
seq_len=1024,
|
| 988 |
+
n_layer=12,
|
| 989 |
+
n_embd=768,
|
| 990 |
+
n_head=12,
|
| 991 |
+
fno_modes=256,
|
| 992 |
+
gla_chunk=64,
|
| 993 |
+
ffn_hidden=2048,
|
| 994 |
+
layer_pattern="SSSL",
|
| 995 |
+
)
|
| 996 |
+
for k, v in overrides.items():
|
| 997 |
+
setattr(cfg, k, v)
|
| 998 |
+
return cfg
|
| 999 |
+
|
| 1000 |
+
|
| 1001 |
+
def smoke_config(**overrides) -> CPUGPTConfig:
|
| 1002 |
+
cfg = CPUGPTConfig(
|
| 1003 |
+
vocab_size=50257,
|
| 1004 |
+
seq_len=256,
|
| 1005 |
+
n_layer=4,
|
| 1006 |
+
n_embd=256,
|
| 1007 |
+
n_head=4,
|
| 1008 |
+
fno_modes=64,
|
| 1009 |
+
gla_chunk=64,
|
| 1010 |
+
ffn_hidden=512,
|
| 1011 |
+
layer_pattern="SSSL",
|
| 1012 |
+
)
|
| 1013 |
+
for k, v in overrides.items():
|
| 1014 |
+
setattr(cfg, k, v)
|
| 1015 |
+
return cfg
|
| 1016 |
+
|
| 1017 |
+
|
| 1018 |
+
def gpt2_8b_config() -> CPUGPTConfig:
|
| 1019 |
+
return CPUGPTConfig(
|
| 1020 |
+
n_layer=32,
|
| 1021 |
+
n_embd=4096,
|
| 1022 |
+
n_head=32,
|
| 1023 |
+
ffn_hidden=14336,
|
| 1024 |
+
fno_modes=512,
|
| 1025 |
+
gla_chunk=256,
|
| 1026 |
+
seq_len=2048,
|
| 1027 |
+
layer_pattern="SSSL",
|
| 1028 |
+
)
|
| 1029 |
+
|
| 1030 |
+
|
| 1031 |
+
def gpt2_1b_config() -> CPUGPTConfig:
|
| 1032 |
+
return CPUGPTConfig(
|
| 1033 |
+
n_layer=24,
|
| 1034 |
+
n_embd=2048,
|
| 1035 |
+
n_head=16,
|
| 1036 |
+
ffn_hidden=5632,
|
| 1037 |
+
fno_modes=512,
|
| 1038 |
+
gla_chunk=256,
|
| 1039 |
+
seq_len=2048,
|
| 1040 |
+
layer_pattern="SSSL",
|
| 1041 |
+
vocab_size=50257,
|
| 1042 |
+
)
|
| 1043 |
+
|
| 1044 |
+
|
| 1045 |
+
def byte125m_config(**overrides) -> CPUGPTConfig:
|
| 1046 |
+
cfg = CPUGPTConfig(
|
| 1047 |
+
vocab_size=261,
|
| 1048 |
+
seq_len=16384,
|
| 1049 |
+
n_layer=12,
|
| 1050 |
+
n_embd=1024,
|
| 1051 |
+
n_head=16,
|
| 1052 |
+
fno_modes=256,
|
| 1053 |
+
gla_chunk=512,
|
| 1054 |
+
ffn_hidden=2816,
|
| 1055 |
+
layer_pattern="SSSL",
|
| 1056 |
+
fft_dtype="fp32",
|
| 1057 |
+
use_flash_fft=True,
|
| 1058 |
+
)
|
| 1059 |
+
for k, v in overrides.items():
|
| 1060 |
+
setattr(cfg, k, v)
|
| 1061 |
+
return cfg
|
| 1062 |
+
|
| 1063 |
+
|
| 1064 |
+
def gpt2_1b_optimized_config() -> CPUGPTConfig:
|
| 1065 |
+
return CPUGPTConfig(
|
| 1066 |
+
n_layer=24,
|
| 1067 |
+
n_embd=2048,
|
| 1068 |
+
n_head=16,
|
| 1069 |
+
ffn_hidden=5632,
|
| 1070 |
+
fno_modes=512,
|
| 1071 |
+
gla_chunk=512,
|
| 1072 |
+
seq_len=2048,
|
| 1073 |
+
layer_pattern="SSSL",
|
| 1074 |
+
vocab_size=50257,
|
| 1075 |
+
fft_dtype="bf16",
|
| 1076 |
+
use_flash_fft=True,
|
| 1077 |
+
)
|
| 1078 |
+
|
| 1079 |
+
|
| 1080 |
+
QWEN_CODER_VOCAB = 152064
|
| 1081 |
+
QWEN3_4B_VOCAB = 151936
|
| 1082 |
+
|
| 1083 |
+
|
| 1084 |
+
def code_3b_config(**overrides) -> CPUGPTConfig:
|
| 1085 |
+
cfg = CPUGPTConfig(
|
| 1086 |
+
vocab_size=QWEN_CODER_VOCAB,
|
| 1087 |
+
seq_len=4096,
|
| 1088 |
+
n_layer=28,
|
| 1089 |
+
n_embd=3072,
|
| 1090 |
+
n_head=24,
|
| 1091 |
+
fno_modes=512,
|
| 1092 |
+
gla_chunk=256,
|
| 1093 |
+
ffn_hidden=8192,
|
| 1094 |
+
layer_pattern="SSSL",
|
| 1095 |
+
gla_delta=True,
|
| 1096 |
+
sliding_window=0,
|
| 1097 |
+
)
|
| 1098 |
+
for k, v in overrides.items():
|
| 1099 |
+
setattr(cfg, k, v)
|
| 1100 |
+
return cfg
|
| 1101 |
+
|
| 1102 |
+
|
| 1103 |
+
def code_3b_exact_config(**overrides) -> CPUGPTConfig:
|
| 1104 |
+
cfg = CPUGPTConfig(
|
| 1105 |
+
vocab_size=QWEN_CODER_VOCAB,
|
| 1106 |
+
seq_len=4096,
|
| 1107 |
+
n_layer=28,
|
| 1108 |
+
n_embd=3584,
|
| 1109 |
+
n_head=28,
|
| 1110 |
+
fno_modes=512,
|
| 1111 |
+
gla_chunk=256,
|
| 1112 |
+
ffn_hidden=18944,
|
| 1113 |
+
layer_pattern="SSSL",
|
| 1114 |
+
gla_delta=True,
|
| 1115 |
+
sliding_window=0,
|
| 1116 |
+
)
|
| 1117 |
+
for k, v in overrides.items():
|
| 1118 |
+
setattr(cfg, k, v)
|
| 1119 |
+
return cfg
|
| 1120 |
+
|
| 1121 |
+
|
| 1122 |
+
def code_4b_config(**overrides) -> CPUGPTConfig:
|
| 1123 |
+
cfg = CPUGPTConfig(
|
| 1124 |
+
vocab_size=QWEN3_4B_VOCAB,
|
| 1125 |
+
seq_len=4096,
|
| 1126 |
+
n_layer=36,
|
| 1127 |
+
n_embd=2560,
|
| 1128 |
+
n_head=20,
|
| 1129 |
+
fno_modes=512,
|
| 1130 |
+
gla_chunk=256,
|
| 1131 |
+
ffn_hidden=9728,
|
| 1132 |
+
layer_pattern="SSSL",
|
| 1133 |
+
gla_delta=True,
|
| 1134 |
+
sliding_window=0,
|
| 1135 |
+
)
|
| 1136 |
+
for k, v in overrides.items():
|
| 1137 |
+
setattr(cfg, k, v)
|
| 1138 |
+
return cfg
|
| 1139 |
+
|
| 1140 |
+
|
| 1141 |
+
def code_1b_config(**overrides) -> CPUGPTConfig:
|
| 1142 |
+
cfg = CPUGPTConfig(
|
| 1143 |
+
vocab_size=QWEN_CODER_VOCAB,
|
| 1144 |
+
seq_len=4096,
|
| 1145 |
+
n_layer=24,
|
| 1146 |
+
n_embd=2048,
|
| 1147 |
+
n_head=16,
|
| 1148 |
+
fno_modes=512,
|
| 1149 |
+
gla_chunk=256,
|
| 1150 |
+
ffn_hidden=5632,
|
| 1151 |
+
layer_pattern="SSSL",
|
| 1152 |
+
gla_delta=True,
|
| 1153 |
+
sliding_window=0,
|
| 1154 |
+
)
|
| 1155 |
+
for k, v in overrides.items():
|
| 1156 |
+
setattr(cfg, k, v)
|
| 1157 |
+
return cfg
|
| 1158 |
+
|
| 1159 |
+
|
| 1160 |
+
def code_1p5b_exact_config(**overrides) -> CPUGPTConfig:
|
| 1161 |
+
cfg = CPUGPTConfig(
|
| 1162 |
+
vocab_size=151936,
|
| 1163 |
+
seq_len=4096,
|
| 1164 |
+
n_layer=28,
|
| 1165 |
+
n_embd=1536,
|
| 1166 |
+
n_head=12,
|
| 1167 |
+
fno_modes=512,
|
| 1168 |
+
gla_chunk=256,
|
| 1169 |
+
ffn_hidden=8960,
|
| 1170 |
+
layer_pattern="SSSL",
|
| 1171 |
+
gla_delta=True,
|
| 1172 |
+
sliding_window=0,
|
| 1173 |
+
)
|
| 1174 |
+
for k, v in overrides.items():
|
| 1175 |
+
setattr(cfg, k, v)
|
| 1176 |
+
return cfg
|
| 1177 |
+
|
| 1178 |
+
|
| 1179 |
+
def arc_a_swa512_config(**overrides) -> CPUGPTConfig:
|
| 1180 |
+
cfg = code_3b_config(swa_window=512)
|
| 1181 |
+
for k, v in overrides.items():
|
| 1182 |
+
setattr(cfg, k, v)
|
| 1183 |
+
return cfg
|
| 1184 |
+
|
| 1185 |
+
|
| 1186 |
+
def arc_c_samba_k6_config(**overrides) -> CPUGPTConfig:
|
| 1187 |
+
cfg = code_3b_config(attn_layer_every=6, attn_full=False, attn_window=512)
|
| 1188 |
+
for k, v in overrides.items():
|
| 1189 |
+
setattr(cfg, k, v)
|
| 1190 |
+
return cfg
|
| 1191 |
+
|
| 1192 |
+
|
| 1193 |
+
def arc_c_samba_k3_config(**overrides) -> CPUGPTConfig:
|
| 1194 |
+
cfg = code_3b_config(attn_layer_every=3, attn_full=False, attn_window=512)
|
| 1195 |
+
for k, v in overrides.items():
|
| 1196 |
+
setattr(cfg, k, v)
|
| 1197 |
+
return cfg
|
| 1198 |
+
|
| 1199 |
+
|
| 1200 |
+
def arc_ub_full4_config(**overrides) -> CPUGPTConfig:
|
| 1201 |
+
cfg = code_3b_config(attn_layer_every=7, attn_full=True)
|
| 1202 |
+
for k, v in overrides.items():
|
| 1203 |
+
setattr(cfg, k, v)
|
| 1204 |
+
return cfg
|
| 1205 |
+
|
| 1206 |
+
|
| 1207 |
+
def arc_d_bigstate_config(**overrides) -> CPUGPTConfig:
|
| 1208 |
+
cfg = code_3b_config(gdn_expand_v=2.0)
|
| 1209 |
+
for k, v in overrides.items():
|
| 1210 |
+
setattr(cfg, k, v)
|
| 1211 |
+
return cfg
|
| 1212 |
+
|
| 1213 |
+
|
| 1214 |
+
def arc_swadelta_config(**overrides) -> CPUGPTConfig:
|
| 1215 |
+
cfg = code_3b_config(swa_fused_window=512)
|
| 1216 |
+
for k, v in overrides.items():
|
| 1217 |
+
setattr(cfg, k, v)
|
| 1218 |
+
return cfg
|
| 1219 |
+
|
| 1220 |
+
|
| 1221 |
+
def code_smoke_config(**overrides) -> CPUGPTConfig:
|
| 1222 |
+
cfg = CPUGPTConfig(
|
| 1223 |
+
vocab_size=QWEN_CODER_VOCAB,
|
| 1224 |
+
seq_len=256,
|
| 1225 |
+
n_layer=4,
|
| 1226 |
+
n_embd=256,
|
| 1227 |
+
n_head=4,
|
| 1228 |
+
fno_modes=64,
|
| 1229 |
+
gla_chunk=64,
|
| 1230 |
+
ffn_hidden=512,
|
| 1231 |
+
layer_pattern="SSSL",
|
| 1232 |
+
gla_delta=False,
|
| 1233 |
+
)
|
| 1234 |
+
for k, v in overrides.items():
|
| 1235 |
+
setattr(cfg, k, v)
|
| 1236 |
+
return cfg
|
| 1237 |
+
|
| 1238 |
+
|
| 1239 |
+
def get_config(name: str) -> CPUGPTConfig:
|
| 1240 |
+
configs = {
|
| 1241 |
+
"gpt2-small": gpt2_small_config,
|
| 1242 |
+
"smoke": smoke_config,
|
| 1243 |
+
"gpt2-8b": gpt2_8b_config,
|
| 1244 |
+
"gpt2-1b": gpt2_1b_config,
|
| 1245 |
+
"gpt2-1b-optimized": gpt2_1b_optimized_config,
|
| 1246 |
+
"byte-125m": byte125m_config,
|
| 1247 |
+
"code-3b": code_3b_config,
|
| 1248 |
+
"code-3b-exact": code_3b_exact_config,
|
| 1249 |
+
"code-4b": code_4b_config,
|
| 1250 |
+
"code-1b": code_1b_config,
|
| 1251 |
+
"code-1.5b-exact": code_1p5b_exact_config,
|
| 1252 |
+
"code-smoke": code_smoke_config,
|
| 1253 |
+
"arc-a-swa512": arc_a_swa512_config,
|
| 1254 |
+
"arc-swadelta": arc_swadelta_config,
|
| 1255 |
+
"arc-c-samba-k6": arc_c_samba_k6_config,
|
| 1256 |
+
"arc-c-samba-k3": arc_c_samba_k3_config,
|
| 1257 |
+
"arc-ub-full4": arc_ub_full4_config,
|
| 1258 |
+
"arc-d-bigstate": arc_d_bigstate_config,
|
| 1259 |
+
}
|
| 1260 |
+
if name not in configs:
|
| 1261 |
+
raise ValueError(f"Unknown config '{name}'. Available: {list(configs.keys())}")
|
| 1262 |
+
return configs[name]()
|
model_int8.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ba877fe6d1bf500906eef6b7cbbd1fdc10127af8b5286b37d228db94314b2a8b
|
| 3 |
+
size 2081695032
|
modeling.py
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
import json
|
| 3 |
+
import os
|
| 4 |
+
import time
|
| 5 |
+
from typing import Optional
|
| 6 |
+
|
| 7 |
+
os.environ.setdefault("CUDA_VISIBLE_DEVICES", "")
|
| 8 |
+
os.environ.setdefault("HIP_VISIBLE_DEVICES", "")
|
| 9 |
+
import torch
|
| 10 |
+
import torch.nn as nn
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def _read_config(weights_dir: str) -> dict:
|
| 14 |
+
path = os.path.join(weights_dir, "config.json")
|
| 15 |
+
if not os.path.exists(path):
|
| 16 |
+
path = weights_dir if weights_dir.endswith(".json") else path
|
| 17 |
+
with open(path) as f:
|
| 18 |
+
return json.load(f)
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def _build_config(cfg_json: dict):
|
| 22 |
+
from model_cpu_gpt2 import CPUGPTConfig
|
| 23 |
+
|
| 24 |
+
return CPUGPTConfig(
|
| 25 |
+
vocab_size=cfg_json["vocab_size"],
|
| 26 |
+
seq_len=cfg_json.get("seq_len", 1024),
|
| 27 |
+
n_layer=cfg_json["n_layer"],
|
| 28 |
+
n_embd=cfg_json["n_embd"],
|
| 29 |
+
n_head=cfg_json["n_head"],
|
| 30 |
+
ffn_hidden=cfg_json["ffn_hidden"],
|
| 31 |
+
layer_pattern=cfg_json.get("layer_pattern", "SSSL"),
|
| 32 |
+
gla_delta=cfg_json.get("gla_delta", True),
|
| 33 |
+
fno_modes=cfg_json.get("fno_modes", 512),
|
| 34 |
+
gla_chunk=cfg_json.get("gla_chunk", 64),
|
| 35 |
+
landmark_layer_every=cfg_json.get("landmark_layer_every", 0),
|
| 36 |
+
landmark_chunk=cfg_json.get("landmark_chunk", 32),
|
| 37 |
+
landmark_max=cfg_json.get("landmark_max", 64),
|
| 38 |
+
attn_layer_every=cfg_json.get("attn_layer_every", 0),
|
| 39 |
+
dropout=0.0,
|
| 40 |
+
)
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
class FelaLM:
|
| 44 |
+
def __init__(self, model, cfg, tokenizer, cfg_json):
|
| 45 |
+
self.model = model
|
| 46 |
+
self.cfg = cfg
|
| 47 |
+
self.tok = tokenizer
|
| 48 |
+
self.cfg_json = cfg_json
|
| 49 |
+
|
| 50 |
+
def _tid(name):
|
| 51 |
+
i = tokenizer.token_to_id(name)
|
| 52 |
+
return i if i is not None and i >= 0 else None
|
| 53 |
+
|
| 54 |
+
self.fim_prefix = _tid("<|fim_prefix|>")
|
| 55 |
+
self.fim_suffix = _tid("<|fim_suffix|>")
|
| 56 |
+
self.fim_middle = _tid("<|fim_middle|>")
|
| 57 |
+
self.fim_pad = _tid("<|fim_pad|>")
|
| 58 |
+
self.eot = _tid("<|endoftext|>")
|
| 59 |
+
self.fim_ok = None not in (self.fim_prefix, self.fim_suffix, self.fim_middle)
|
| 60 |
+
self._stops = {
|
| 61 |
+
t
|
| 62 |
+
for t in (
|
| 63 |
+
self.fim_prefix,
|
| 64 |
+
self.fim_suffix,
|
| 65 |
+
self.fim_middle,
|
| 66 |
+
self.fim_pad,
|
| 67 |
+
self.eot,
|
| 68 |
+
)
|
| 69 |
+
if t is not None
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
@torch.no_grad()
|
| 73 |
+
def complete(
|
| 74 |
+
self,
|
| 75 |
+
prefix: str,
|
| 76 |
+
suffix: str = "",
|
| 77 |
+
max_tokens: int = 40,
|
| 78 |
+
temperature: float = 0.0,
|
| 79 |
+
single_line: bool = True,
|
| 80 |
+
) -> dict:
|
| 81 |
+
prefix = prefix or ""
|
| 82 |
+
suffix = suffix or ""
|
| 83 |
+
used_fim = bool(suffix.strip()) and self.fim_ok
|
| 84 |
+
if used_fim:
|
| 85 |
+
ids = (
|
| 86 |
+
[self.fim_prefix]
|
| 87 |
+
+ self.tok.encode(prefix).ids
|
| 88 |
+
+ [self.fim_suffix]
|
| 89 |
+
+ self.tok.encode(suffix).ids
|
| 90 |
+
+ [self.fim_middle]
|
| 91 |
+
)
|
| 92 |
+
else:
|
| 93 |
+
ids = self.tok.encode(prefix).ids
|
| 94 |
+
if not ids:
|
| 95 |
+
ids = [self.eot] if self.eot is not None else [0]
|
| 96 |
+
t0 = time.perf_counter()
|
| 97 |
+
states = self.model.init_state(batch_size=1)
|
| 98 |
+
logits = None
|
| 99 |
+
for tok_id in ids:
|
| 100 |
+
logits, states = self.model.step(
|
| 101 |
+
torch.tensor([tok_id], dtype=torch.long), states
|
| 102 |
+
)
|
| 103 |
+
prefill_ms = (time.perf_counter() - t0) * 1000.0
|
| 104 |
+
out_ids = []
|
| 105 |
+
td = time.perf_counter()
|
| 106 |
+
for _ in range(max_tokens):
|
| 107 |
+
if temperature and temperature > 0:
|
| 108 |
+
probs = torch.softmax(logits.float().reshape(-1) / temperature, -1)
|
| 109 |
+
nxt = int(torch.multinomial(probs, 1).item())
|
| 110 |
+
else:
|
| 111 |
+
nxt = int(logits.float().reshape(-1).argmax().item())
|
| 112 |
+
if nxt in self._stops:
|
| 113 |
+
break
|
| 114 |
+
out_ids.append(nxt)
|
| 115 |
+
piece = self.tok.decode(out_ids)
|
| 116 |
+
if single_line and "\n" in piece:
|
| 117 |
+
break
|
| 118 |
+
logits, states = self.model.step(
|
| 119 |
+
torch.tensor([nxt], dtype=torch.long), states
|
| 120 |
+
)
|
| 121 |
+
decode_ms = (time.perf_counter() - td) * 1000.0
|
| 122 |
+
text = self.tok.decode(out_ids) if out_ids else ""
|
| 123 |
+
if single_line:
|
| 124 |
+
text = text.split("\n", 1)[0]
|
| 125 |
+
n = len(out_ids)
|
| 126 |
+
return {
|
| 127 |
+
"middle": text,
|
| 128 |
+
"n_tokens": n,
|
| 129 |
+
"used_fim": used_fim,
|
| 130 |
+
"prompt_tokens": len(ids),
|
| 131 |
+
"prefill_ms": round(prefill_ms, 1),
|
| 132 |
+
"decode_ms": round(decode_ms, 1),
|
| 133 |
+
"tok_per_s": round(n / (decode_ms / 1000.0), 2)
|
| 134 |
+
if decode_ms > 0 and n
|
| 135 |
+
else 0.0,
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
def _read_bf16_state(weights_dir: str) -> dict:
|
| 140 |
+
from safetensors import safe_open
|
| 141 |
+
|
| 142 |
+
st = {}
|
| 143 |
+
path = os.path.join(weights_dir, "model.safetensors")
|
| 144 |
+
with safe_open(path, framework="pt", device="cpu") as f:
|
| 145 |
+
for k in f.keys():
|
| 146 |
+
st[k] = f.get_tensor(k).float()
|
| 147 |
+
return st
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
def _read_int8_state(weights_dir: str) -> dict:
|
| 151 |
+
from safetensors import safe_open
|
| 152 |
+
|
| 153 |
+
st = {}
|
| 154 |
+
path = os.path.join(weights_dir, "model_int8.safetensors")
|
| 155 |
+
with safe_open(path, framework="pt", device="cpu") as f:
|
| 156 |
+
keys = list(f.keys())
|
| 157 |
+
for k in keys:
|
| 158 |
+
if k.startswith("keep."):
|
| 159 |
+
st[k[len("keep.") :]] = f.get_tensor(k).float()
|
| 160 |
+
for k in keys:
|
| 161 |
+
if k.startswith("int8."):
|
| 162 |
+
base = k[len("int8.") :]
|
| 163 |
+
w = f.get_tensor(k).float()
|
| 164 |
+
s = f.get_tensor("scale." + base).float()
|
| 165 |
+
st[base] = w * s.reshape([-1] + [1] * (w.dim() - 1))
|
| 166 |
+
return st
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
def _apply_state(model, st: dict) -> None:
|
| 170 |
+
params = dict(model.named_parameters())
|
| 171 |
+
params.update(dict(model.named_buffers()))
|
| 172 |
+
keys = set(st)
|
| 173 |
+
for k in keys:
|
| 174 |
+
dst = params.get(k)
|
| 175 |
+
if dst is None:
|
| 176 |
+
raise KeyError(f"Checkpoint key {k!r} has no home in the model")
|
| 177 |
+
with torch.no_grad():
|
| 178 |
+
dst.copy_(st[k])
|
| 179 |
+
missing = set(params) - keys
|
| 180 |
+
if missing:
|
| 181 |
+
raise KeyError(f"Missing {len(missing)} params, e.g. {sorted(missing)[:5]}")
|
| 182 |
+
|
| 183 |
+
|
| 184 |
+
def _resolve_quant(weights_dir: str, quant: str) -> str:
|
| 185 |
+
if quant == "auto":
|
| 186 |
+
has_int8 = os.path.exists(os.path.join(weights_dir, "model_int8.safetensors"))
|
| 187 |
+
has_bf16 = os.path.exists(os.path.join(weights_dir, "model.safetensors"))
|
| 188 |
+
return "bf16" if has_bf16 else ("int8" if has_int8 else "bf16")
|
| 189 |
+
return quant
|
| 190 |
+
|
| 191 |
+
|
| 192 |
+
def load_model(
|
| 193 |
+
weights_dir: str = ".", threads: Optional[int] = None, quant: str = "bf16"
|
| 194 |
+
) -> FelaLM:
|
| 195 |
+
from model_cpu_gpt2 import CPUGPT
|
| 196 |
+
from cpu_patch import enable_cpu_delta
|
| 197 |
+
from tokenizers import Tokenizer
|
| 198 |
+
|
| 199 |
+
if threads:
|
| 200 |
+
torch.set_num_threads(threads)
|
| 201 |
+
if weights_dir.endswith(".safetensors"):
|
| 202 |
+
weights_dir = os.path.dirname(os.path.abspath(weights_dir)) or "."
|
| 203 |
+
cfg_json = _read_config(weights_dir)
|
| 204 |
+
cfg = _build_config(cfg_json)
|
| 205 |
+
model = CPUGPT(cfg)
|
| 206 |
+
model.lm_head = nn.Linear(cfg.n_embd, cfg.vocab_size, bias=False)
|
| 207 |
+
quant = _resolve_quant(weights_dir, quant)
|
| 208 |
+
if quant == "int8":
|
| 209 |
+
st = _read_int8_state(weights_dir)
|
| 210 |
+
else:
|
| 211 |
+
st = _read_bf16_state(weights_dir)
|
| 212 |
+
_apply_state(model, st)
|
| 213 |
+
model.eval()
|
| 214 |
+
enable_cpu_delta(model)
|
| 215 |
+
model.prepare_inference()
|
| 216 |
+
tok_path = os.path.join(weights_dir, "tokenizer.json")
|
| 217 |
+
tokenizer = Tokenizer.from_file(tok_path)
|
| 218 |
+
return FelaLM(model, cfg, tokenizer, cfg_json)
|
| 219 |
+
|
| 220 |
+
|
| 221 |
+
def from_pretrained(repo_id: str = "lowdown-labs/FELA-autocomplete") -> FelaLM:
|
| 222 |
+
from huggingface_hub import hf_hub_download
|
| 223 |
+
|
| 224 |
+
d = os.path.dirname(hf_hub_download(repo_id, "config.json"))
|
| 225 |
+
hf_hub_download(repo_id, "model.safetensors")
|
| 226 |
+
hf_hub_download(repo_id, "tokenizer.json")
|
| 227 |
+
hf_hub_download(repo_id, "model_cpu_gpt2.py")
|
| 228 |
+
for f in ("cpu_delta.py", "cpu_landmark.py", "cpu_swa.py", "cpu_patch.py"):
|
| 229 |
+
hf_hub_download(repo_id, f)
|
| 230 |
+
return load_model(d)
|
modeling_fela.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
| 5 |
+
import torch
|
| 6 |
+
import torch.nn as nn
|
| 7 |
+
from transformers import PreTrainedModel
|
| 8 |
+
from transformers.modeling_outputs import CausalLMOutput
|
| 9 |
+
|
| 10 |
+
from .configuration_fela import FelaConfig
|
| 11 |
+
from .cpu_delta import CPUGatedDeltaNet as _cd
|
| 12 |
+
from .cpu_landmark import CPULandmark as _cl
|
| 13 |
+
from .cpu_swa import CPUSlidingWindow as _cs
|
| 14 |
+
from .model_cpu_gpt2 import CPUGPT, CPUGPTConfig
|
| 15 |
+
from .cpu_patch import enable_cpu_delta
|
| 16 |
+
|
| 17 |
+
_KEEP = (_cd, _cl, _cs)
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
class FelaForCausalLM(PreTrainedModel):
|
| 21 |
+
config_class = FelaConfig
|
| 22 |
+
base_model_prefix = "model"
|
| 23 |
+
_tied_weights_keys = []
|
| 24 |
+
_no_split_modules = []
|
| 25 |
+
|
| 26 |
+
def __init__(self, config):
|
| 27 |
+
super().__init__(config)
|
| 28 |
+
cfg = CPUGPTConfig(
|
| 29 |
+
vocab_size=config.vocab_size,
|
| 30 |
+
seq_len=config.seq_len,
|
| 31 |
+
n_layer=config.n_layer,
|
| 32 |
+
n_embd=config.n_embd,
|
| 33 |
+
n_head=config.n_head,
|
| 34 |
+
ffn_hidden=config.ffn_hidden,
|
| 35 |
+
layer_pattern=config.layer_pattern,
|
| 36 |
+
gla_delta=config.gla_delta,
|
| 37 |
+
fno_modes=config.fno_modes,
|
| 38 |
+
gla_chunk=config.gla_chunk,
|
| 39 |
+
landmark_layer_every=config.landmark_layer_every,
|
| 40 |
+
landmark_chunk=config.landmark_chunk,
|
| 41 |
+
landmark_max=config.landmark_max,
|
| 42 |
+
attn_layer_every=config.attn_layer_every,
|
| 43 |
+
dropout=0.0,
|
| 44 |
+
)
|
| 45 |
+
self.model = CPUGPT(cfg)
|
| 46 |
+
self.model.lm_head = nn.Linear(config.n_embd, config.vocab_size, bias=False)
|
| 47 |
+
self._prepared = False
|
| 48 |
+
self.post_init()
|
| 49 |
+
|
| 50 |
+
def get_input_embeddings(self):
|
| 51 |
+
return self.model.wte
|
| 52 |
+
|
| 53 |
+
def set_input_embeddings(self, value):
|
| 54 |
+
self.model.wte = value
|
| 55 |
+
|
| 56 |
+
def get_output_embeddings(self):
|
| 57 |
+
return self.model.lm_head
|
| 58 |
+
|
| 59 |
+
def set_output_embeddings(self, value):
|
| 60 |
+
self.model.lm_head = value
|
| 61 |
+
|
| 62 |
+
def _ensure_prepared(self):
|
| 63 |
+
if not self._prepared:
|
| 64 |
+
enable_cpu_delta(self.model)
|
| 65 |
+
self.model.prepare_inference()
|
| 66 |
+
self._prepared = True
|
| 67 |
+
|
| 68 |
+
def forward(
|
| 69 |
+
self, input_ids=None, attention_mask=None, labels=None, use_cache=None, **kwargs
|
| 70 |
+
):
|
| 71 |
+
self._ensure_prepared()
|
| 72 |
+
logits = self.model(input_ids)
|
| 73 |
+
loss = None
|
| 74 |
+
if labels is not None:
|
| 75 |
+
sl = logits[..., :-1, :].contiguous()
|
| 76 |
+
lb = labels[..., 1:].contiguous()
|
| 77 |
+
loss = nn.functional.cross_entropy(sl.view(-1, sl.size(-1)), lb.view(-1))
|
| 78 |
+
return CausalLMOutput(loss=loss, logits=logits)
|
| 79 |
+
|
| 80 |
+
def prepare_inputs_for_generation(self, input_ids, **kwargs):
|
| 81 |
+
return {"input_ids": input_ids}
|
| 82 |
+
|
| 83 |
+
def can_generate(self):
|
| 84 |
+
return True
|
quickstart/README.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Quickstart
|
| 2 |
+
|
| 3 |
+
Load the FELA LLM 1.5 code model and run a real fill in the middle completion on CPU.
|
| 4 |
+
Uses the self contained loader in `../modeling.py`.
|
| 5 |
+
|
| 6 |
+
## Steps
|
| 7 |
+
|
| 8 |
+
1. Install the pinned requirements (CPU PyTorch):
|
| 9 |
+
|
| 10 |
+
```bash
|
| 11 |
+
pip install -r requirements.txt
|
| 12 |
+
```
|
| 13 |
+
|
| 14 |
+
2. Point the loader at the directory that holds the weights (this repo). The model
|
| 15 |
+
ships as `model.safetensors` next to `config.json` and `tokenizer.json`:
|
| 16 |
+
|
| 17 |
+
```bash
|
| 18 |
+
export FELA_LLM_WEIGHTS=/path/to/this/repo
|
| 19 |
+
python run.py
|
| 20 |
+
```
|
| 21 |
+
|
| 22 |
+
## Load from Python
|
| 23 |
+
|
| 24 |
+
```python
|
| 25 |
+
from modeling import load_model
|
| 26 |
+
m = load_model("/path/to/this/repo")
|
| 27 |
+
|
| 28 |
+
# Fill in the middle: give the code before and after the cursor, get the middle
|
| 29 |
+
r = m.complete("def add(a, b):\n ", suffix="\nresult = add(2, 3)\n")
|
| 30 |
+
print(r["middle"]) # e.g. " return a + b"
|
| 31 |
+
|
| 32 |
+
# Plain autocomplete: continue a single line
|
| 33 |
+
print(m.complete("import numpy as ")["middle"]) # e.g. " np"
|
| 34 |
+
```
|
| 35 |
+
|
| 36 |
+
`complete` is greedy by default, so the same prompt gives the same real output every
|
| 37 |
+
time. When you pass a non empty `suffix` and the tokenizer has the FIM tokens, it uses
|
| 38 |
+
the fill in the middle layout `<|fim_prefix|> P <|fim_suffix|> S <|fim_middle|>` and
|
| 39 |
+
writes the code that belongs between them; otherwise it continues the prefix.
|
| 40 |
+
|
| 41 |
+
## What to expect
|
| 42 |
+
|
| 43 |
+
This is the final fill in the middle model. Single line patterns land well (imports,
|
| 44 |
+
obvious returns, boilerplate); multi line blocks and novel logic are outside what it is
|
| 45 |
+
built for. Every completion is a genuine forward of the model, never a lookup. The
|
| 46 |
+
reference load path here runs on CPU with no GPU. For fast production serving the same
|
| 47 |
+
weights run int8 on the CPU native FELA server.
|
quickstart/requirements.txt
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
torch==2.8.0
|
| 2 |
+
safetensors==0.5.3
|
| 3 |
+
tokenizers==0.22.2
|
| 4 |
+
huggingface-hub==0.34.4
|
| 5 |
+
flash-linear-attention==0.5.1
|
quickstart/run.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
import os
|
| 3 |
+
import sys
|
| 4 |
+
import torch
|
| 5 |
+
|
| 6 |
+
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
|
| 7 |
+
from modeling import load_model
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def main():
|
| 11 |
+
ap = argparse.ArgumentParser()
|
| 12 |
+
ap.add_argument(
|
| 13 |
+
"--weights",
|
| 14 |
+
default=os.environ.get("FELA_LLM_WEIGHTS", ".."),
|
| 15 |
+
help="Dir with model.safetensors, config.json, tokenizer.json",
|
| 16 |
+
)
|
| 17 |
+
ap.add_argument("--threads", type=int, default=4)
|
| 18 |
+
args = ap.parse_args()
|
| 19 |
+
torch.set_num_threads(args.threads)
|
| 20 |
+
print("Loading FELA LLM 1.5 on CPU (no GPU needed)...")
|
| 21 |
+
m = load_model(args.weights, threads=args.threads)
|
| 22 |
+
print(
|
| 23 |
+
f"Loaded {m.cfg_json.get('n_params', 0) / 1000000000.0:.2f}B params, fim={m.fim_ok}\n"
|
| 24 |
+
)
|
| 25 |
+
print("Fill in the middle: prefix + suffix -> the model writes the middle")
|
| 26 |
+
prefix = "def add(a, b):\n "
|
| 27 |
+
suffix = "\nresult = add(2, 3)\n"
|
| 28 |
+
r = m.complete(prefix, suffix, max_tokens=16)
|
| 29 |
+
print(f" Prefix: {prefix!r}")
|
| 30 |
+
print(f" Suffix: {suffix!r}")
|
| 31 |
+
print(
|
| 32 |
+
f" Middle: {r['middle']!r} (fim={r['used_fim']}, {r['n_tokens']} tokens, {r['tok_per_s']} tok/s)\n"
|
| 33 |
+
)
|
| 34 |
+
print("Plain autocomplete: continue a single line")
|
| 35 |
+
for prefix in ["import numpy as ", "from fastapi import ", "for i in range("]:
|
| 36 |
+
r = m.complete(prefix, "", max_tokens=12)
|
| 37 |
+
print(f" {prefix!r} -> {r['middle']!r}")
|
| 38 |
+
print(
|
| 39 |
+
"\nThis is the final fill in the middle model. Single line completions land well; multi line blocks and novel logic are outside what it is built for. Every completion is a real forward of the model."
|
| 40 |
+
)
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
if __name__ == "__main__":
|
| 44 |
+
main()
|
requirements.txt
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
torch==2.8.0
|
| 2 |
+
safetensors==0.5.3
|
| 3 |
+
tokenizers==0.22.2
|
| 4 |
+
huggingface-hub==0.34.4
|
| 5 |
+
flash-linear-attention==0.5.1
|
space/README.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: FELA LLM 1.5 code completion
|
| 3 |
+
colorFrom: indigo
|
| 4 |
+
colorTo: purple
|
| 5 |
+
sdk: gradio
|
| 6 |
+
sdk_version: 4.44.0
|
| 7 |
+
app_file: app.py
|
| 8 |
+
pinned: false
|
| 9 |
+
license: other
|
| 10 |
+
---
|
| 11 |
+
|
| 12 |
+
# FELA LLM 1.5 code completion
|
| 13 |
+
|
| 14 |
+
Type the code before your cursor (Prefix) and optionally the code after it (Suffix), and
|
| 15 |
+
the model writes the line that goes in between. It runs on a plain CPU with no GPU.
|
| 16 |
+
|
| 17 |
+
## How it works
|
| 18 |
+
|
| 19 |
+
The model reads your prefix and suffix, and when the suffix is present it uses the fill
|
| 20 |
+
in the middle layout so the completion fits between them. It writes one line at a time,
|
| 21 |
+
greedy by default, so the same prompt gives the same real output every time.
|
| 22 |
+
|
| 23 |
+
## What to expect
|
| 24 |
+
|
| 25 |
+
This is the final fill in the middle model. Single line patterns land well (imports,
|
| 26 |
+
obvious returns, boilerplate); multi line blocks and novel logic are outside what it is
|
| 27 |
+
built for. Every completion is a genuine forward of the model, never a lookup. For fast
|
| 28 |
+
production serving the same weights run int8 on the CPU native FELA server.
|
space/app.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
import gradio as gr
|
| 4 |
+
import torch
|
| 5 |
+
|
| 6 |
+
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
|
| 7 |
+
from modeling import load_model
|
| 8 |
+
|
| 9 |
+
WEIGHTS = os.environ.get("FELA_LLM_WEIGHTS", "..")
|
| 10 |
+
try:
|
| 11 |
+
torch.set_num_threads(4)
|
| 12 |
+
MODEL = load_model(WEIGHTS, threads=4)
|
| 13 |
+
except Exception as e:
|
| 14 |
+
MODEL = None
|
| 15 |
+
print(f"[Note] Model not loaded ({e}); the Space reports the input instead.")
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def complete(prefix, suffix, max_tokens):
|
| 19 |
+
if MODEL is None:
|
| 20 |
+
return "Weights not found. Set FELA_LLM_WEIGHTS to the repo directory."
|
| 21 |
+
if not (prefix or "").strip() and (not (suffix or "").strip()):
|
| 22 |
+
return "Type some code before the cursor (prefix), and optionally after it (suffix)."
|
| 23 |
+
r = MODEL.complete(prefix or "", suffix or "", max_tokens=int(max_tokens))
|
| 24 |
+
tag = "fill in the middle" if r["used_fim"] else "continuation"
|
| 25 |
+
return f"{r['middle']}\n\n[{tag}, {r['n_tokens']} tokens, {r['tok_per_s']} tok/s on CPU]"
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
with gr.Blocks(title="FELA LLM 1.5 code completion") as demo:
|
| 29 |
+
gr.Markdown(
|
| 30 |
+
"# FELA LLM 1.5 code completion\nA CPU native code autocomplete model. Type the code before your cursor in Prefix, and optionally the code after your cursor in Suffix, and it writes the line that goes in between. It runs on a plain CPU with no GPU. This is the final fill in the middle model: single line patterns land well, multi line blocks and novel logic are outside what it is built for. Every completion is a real forward of the model."
|
| 31 |
+
)
|
| 32 |
+
prefix = gr.Textbox(
|
| 33 |
+
label="Prefix (code before the cursor)", value="def add(a, b):\n ", lines=4
|
| 34 |
+
)
|
| 35 |
+
suffix = gr.Textbox(
|
| 36 |
+
label="Suffix (code after the cursor, optional)",
|
| 37 |
+
value="\nresult = add(2, 3)\n",
|
| 38 |
+
lines=2,
|
| 39 |
+
)
|
| 40 |
+
max_tokens = gr.Slider(4, 64, value=16, step=1, label="Max tokens")
|
| 41 |
+
out = gr.Textbox(label="Completed middle", lines=4)
|
| 42 |
+
gr.Button("Complete").click(complete, [prefix, suffix, max_tokens], out)
|
| 43 |
+
if __name__ == "__main__":
|
| 44 |
+
demo.launch()
|
space/requirements.txt
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio==4.44.0
|
| 2 |
+
torch==2.8.0
|
| 3 |
+
safetensors==0.5.3
|
| 4 |
+
tokenizers==0.22.2
|
| 5 |
+
huggingface-hub==0.34.4
|
| 6 |
+
flash-linear-attention==0.5.1
|
tokenizer.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
verify.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
import sys
|
| 3 |
+
import torch
|
| 4 |
+
from modeling import load_model
|
| 5 |
+
|
| 6 |
+
VERIFICATION_TOP5 = [319, 516, 22441, 497, 4102]
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def main():
|
| 10 |
+
ap = argparse.ArgumentParser()
|
| 11 |
+
ap.add_argument("--weights", default=".")
|
| 12 |
+
ap.add_argument("--capture", action="store_true")
|
| 13 |
+
args = ap.parse_args()
|
| 14 |
+
torch.set_num_threads(1)
|
| 15 |
+
m = load_model(args.weights, threads=1)
|
| 16 |
+
ids = torch.arange(16, dtype=torch.long).unsqueeze(0) + 100
|
| 17 |
+
with torch.no_grad():
|
| 18 |
+
logits = m.model(ids)
|
| 19 |
+
assert logits.dim() == 3 and logits.size(-1) == m.cfg.vocab_size, (
|
| 20 |
+
f"Bad output shape {tuple(logits.shape)} (expected vocab {m.cfg.vocab_size})"
|
| 21 |
+
)
|
| 22 |
+
assert torch.isfinite(logits).all(), "Non finite logits"
|
| 23 |
+
print(f"Output shape ok {tuple(logits.shape)}")
|
| 24 |
+
top5 = logits[0, -1].topk(5).indices.tolist()
|
| 25 |
+
if args.capture:
|
| 26 |
+
print(f"VERIFICATION_TOP5 = {top5}")
|
| 27 |
+
return
|
| 28 |
+
if top5 != VERIFICATION_TOP5:
|
| 29 |
+
print(
|
| 30 |
+
f"[WARNING] top 5 tokens {top5} differ from the reference {VERIFICATION_TOP5}; small CPU numeric differences can move ties across machines"
|
| 31 |
+
)
|
| 32 |
+
else:
|
| 33 |
+
print("Verification value ok")
|
| 34 |
+
r = m.complete("import numpy as ", "", max_tokens=4)
|
| 35 |
+
print(f"Sample completion: 'import numpy as ' -> {r['middle']!r}")
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
if __name__ == "__main__":
|
| 39 |
+
main()
|