portallib 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- portallib-0.1.0/.gitignore +15 -0
- portallib-0.1.0/CHANGELOG.md +21 -0
- portallib-0.1.0/CITATION.cff +11 -0
- portallib-0.1.0/COMPUTE.md +78 -0
- portallib-0.1.0/Dockerfile +17 -0
- portallib-0.1.0/LICENSE +202 -0
- portallib-0.1.0/PKG-INFO +248 -0
- portallib-0.1.0/README.md +217 -0
- portallib-0.1.0/examples/evaluate_example.py +76 -0
- portallib-0.1.0/examples/launchers/modal_launcher.py +39 -0
- portallib-0.1.0/examples/refit_example.py +117 -0
- portallib-0.1.0/examples/train_example.py +116 -0
- portallib-0.1.0/examples/utils/__init__.py +5 -0
- portallib-0.1.0/examples/utils/loading.py +62 -0
- portallib-0.1.0/pyproject.toml +74 -0
- portallib-0.1.0/scripts/portal_tasks_dataset_card.md +78 -0
- portallib-0.1.0/scripts/prepare_dataset.py +335 -0
- portallib-0.1.0/src/portallib/__init__.py +37 -0
- portallib-0.1.0/src/portallib/config.py +186 -0
- portallib-0.1.0/src/portallib/data.py +124 -0
- portallib-0.1.0/src/portallib/decoder.py +97 -0
- portallib-0.1.0/src/portallib/evaluation.py +323 -0
- portallib-0.1.0/src/portallib/model.py +296 -0
- portallib-0.1.0/src/portallib/training.py +758 -0
- portallib-0.1.0/tests/test_examples.py +54 -0
- portallib-0.1.0/tests/test_portallib.py +722 -0
- portallib-0.1.0/tests/test_prepare_dataset.py +131 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `portallib` are documented here.
|
|
4
|
+
|
|
5
|
+
## 0.1.0 - 2026-07-15
|
|
6
|
+
|
|
7
|
+
Initial public release of `portallib` on PyPI.
|
|
8
|
+
|
|
9
|
+
- Canonical shared task-latent/core architecture with one exact-path alignment per base.
|
|
10
|
+
- Joint multi-source core training, frozen-core target refitting, and normalized evaluation APIs.
|
|
11
|
+
- Deterministic balanced task rounds, EMA loss normalization, per-base latent-gradient
|
|
12
|
+
balancing, learning-rate warmup, checkpointing, and best-validation-epoch selection.
|
|
13
|
+
- Local and Hugging Face dataset loading, canonical JSON serialization, and explicit Hub upload.
|
|
14
|
+
- Standard `save_pretrained`, `from_pretrained`, and `push_to_hub` behavior through
|
|
15
|
+
`ModelHubMixin`.
|
|
16
|
+
- Exact PEFT model materialization and reloadable task-specific PEFT adapter export.
|
|
17
|
+
- Published Qwen3-1.7B and Qwen3-4B source artifacts containing the jointly trained shared core and
|
|
18
|
+
task latents with their respective base alignments.
|
|
19
|
+
- Published 1,000-example-per-task Qwen3-8B and Gemma 3 4B refit artifacts.
|
|
20
|
+
- Pinned source training, target refitting, and evaluation recipes.
|
|
21
|
+
- CPU correctness contracts plus Docker and Modal execution guidance.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use PorTAL, please cite this software."
|
|
3
|
+
title: "PorTAL: Portable Task Adapters for LLMs"
|
|
4
|
+
type: software
|
|
5
|
+
authors:
|
|
6
|
+
- family-names: Geist
|
|
7
|
+
given-names: Benjamin
|
|
8
|
+
repository-code: "https://github.com/ramp-public/portallib"
|
|
9
|
+
url: "https://x.com/RampLabs/status/2072381992285647280"
|
|
10
|
+
version: 0.1.0
|
|
11
|
+
license: Apache-2.0
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Running PorTAL on GPU compute
|
|
2
|
+
|
|
3
|
+
PorTAL training and evaluation are single-process PyTorch workloads. The library is installed from
|
|
4
|
+
PyPI; the repository supplies the editable recipe files and compute launchers. Select
|
|
5
|
+
`train_example.py`, `refit_example.py`, or `evaluate_example.py`, edit its recipe block, and run it.
|
|
6
|
+
Every compute platform follows the same pattern:
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
python examples/train_example.py
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
The compute platform provisions the GPU, preserves the Hugging Face cache and `artifacts/`
|
|
13
|
+
directory, and supplies any required Hugging Face token. The release source and both 1,000-example
|
|
14
|
+
refit settings are documented in [`REPRODUCING.md`](REPRODUCING.md).
|
|
15
|
+
|
|
16
|
+
## Hardware and execution model
|
|
17
|
+
|
|
18
|
+
Source training loads both source models in one process. Refitting loads one trained PorTAL artifact
|
|
19
|
+
and one raw target base; evaluation loads one artifact and its matching raw base. Use one high-memory
|
|
20
|
+
NVIDIA GPU; an H200-class GPU is recommended for the complete two-source recipe. A smaller model or
|
|
21
|
+
CPU can be used for development and contract tests.
|
|
22
|
+
|
|
23
|
+
The examples use one CUDA device and do not use multi-process or multi-node execution.
|
|
24
|
+
|
|
25
|
+
## Local Docker
|
|
26
|
+
|
|
27
|
+
The included [`Dockerfile`](Dockerfile) builds a CUDA training image containing the exact checked-out
|
|
28
|
+
package code and edited recipe. This source-based image is useful for validating a release commit;
|
|
29
|
+
ordinary library installation should use PyPI.
|
|
30
|
+
The default base image can be overridden with `--build-arg PYTORCH_IMAGE=...` when the host requires
|
|
31
|
+
a different PyTorch/CUDA combination.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
docker build -t portallib-training .
|
|
35
|
+
mkdir -p artifacts hf-cache
|
|
36
|
+
docker run --rm --gpus all \
|
|
37
|
+
-e HF_TOKEN \
|
|
38
|
+
-v "$PWD/artifacts:/workspace/portallib/artifacts" \
|
|
39
|
+
-v "$PWD/hf-cache:/cache/huggingface" \
|
|
40
|
+
portallib-training
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The image defaults to `train_example.py`. Override its command for another stage:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
docker run --rm --gpus all \
|
|
47
|
+
-e HF_TOKEN \
|
|
48
|
+
-v "$PWD/artifacts:/workspace/portallib/artifacts" \
|
|
49
|
+
-v "$PWD/hf-cache:/cache/huggingface" \
|
|
50
|
+
portallib-training python examples/refit_example.py
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Choose a base image whose CUDA build supports the assigned GPU. This matters particularly for new
|
|
54
|
+
GPU architectures.
|
|
55
|
+
|
|
56
|
+
## Modal
|
|
57
|
+
|
|
58
|
+
[`examples/launchers/modal_launcher.py`](examples/launchers/modal_launcher.py) is one optional
|
|
59
|
+
compute wrapper. It builds the repository's Docker image, mounts persistent storage at the recipe's
|
|
60
|
+
`artifacts/` directory, and runs the file selected by its `EXAMPLE` constant.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
python -m pip install modal
|
|
64
|
+
modal setup
|
|
65
|
+
modal secret create HF_TOKEN HF_TOKEN=your_token
|
|
66
|
+
modal run examples/launchers/modal_launcher.py
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Download a completed output directory with:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
modal volume get portallib-artifacts portal-qwen-sources ./portal-qwen-sources
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Use the selected example's `OUTPUT_DIR` name when downloading refit results.
|
|
76
|
+
|
|
77
|
+
Edit the launcher's `gpu` value if H200 is unavailable in the selected Modal workspace. The named
|
|
78
|
+
volumes are created automatically and preserve outputs and downloaded models across jobs.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
ARG PYTORCH_IMAGE=pytorch/pytorch:2.7.1-cuda12.8-cudnn9-runtime
|
|
2
|
+
FROM ${PYTORCH_IMAGE}
|
|
3
|
+
|
|
4
|
+
WORKDIR /workspace/portallib
|
|
5
|
+
|
|
6
|
+
ENV HF_HOME=/cache/huggingface \
|
|
7
|
+
PIP_DISABLE_PIP_VERSION_CHECK=1 \
|
|
8
|
+
PYTHONDONTWRITEBYTECODE=1 \
|
|
9
|
+
PYTHONUNBUFFERED=1
|
|
10
|
+
|
|
11
|
+
COPY pyproject.toml README.md LICENSE ./
|
|
12
|
+
COPY src ./src
|
|
13
|
+
COPY examples ./examples
|
|
14
|
+
|
|
15
|
+
RUN python -m pip install --no-cache-dir '.[training]'
|
|
16
|
+
|
|
17
|
+
CMD ["python", "examples/train_example.py"]
|
portallib-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
http://www.apache.org/licenses/
|
|
5
|
+
|
|
6
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
8
|
+
1. Definitions.
|
|
9
|
+
|
|
10
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
13
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
+
the copyright owner that is granting the License.
|
|
15
|
+
|
|
16
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
+
other entities that control, are controlled by, or are under common
|
|
18
|
+
control with that entity. For the purposes of this definition,
|
|
19
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
+
direction or management of such entity, whether by contract or
|
|
21
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
24
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
+
exercising permissions granted by this License.
|
|
26
|
+
|
|
27
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
+
including but not limited to software source code, documentation
|
|
29
|
+
source, and configuration files.
|
|
30
|
+
|
|
31
|
+
"Object" form shall mean any form resulting from mechanical
|
|
32
|
+
transformation or translation of a Source form, including but
|
|
33
|
+
not limited to compiled object code, generated documentation,
|
|
34
|
+
and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
41
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
+
form, that is based on (or derived from) the Work and for which the
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
66
|
+
|
|
67
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
+
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
74
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
+
(except as stated in this section) patent license to make, have made,
|
|
78
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
+
where such license applies only to those patent claims licensable
|
|
80
|
+
by such Contributor that are necessarily infringed by their
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
89
|
+
|
|
90
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
+
modifications, and in Source or Object form, provided that You
|
|
93
|
+
meet the following conditions:
|
|
94
|
+
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
98
|
+
(b) You must cause any modified files to carry prominent notices
|
|
99
|
+
stating that You changed the files; and
|
|
100
|
+
|
|
101
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
+
that You distribute, all copyright, patent, trademark, and
|
|
103
|
+
attribution notices from the Source form of the Work,
|
|
104
|
+
excluding those notices that do not pertain to any part of
|
|
105
|
+
the Derivative Works; and
|
|
106
|
+
|
|
107
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding those notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
130
|
+
|
|
131
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
+
this License, without any additional terms or conditions.
|
|
135
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
+
the terms of any separate license agreement you may have executed
|
|
137
|
+
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
139
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
144
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
+
implied, including, without limitation, any warranties or conditions
|
|
149
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
152
|
+
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
179
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
+
|
|
181
|
+
To apply the Apache License to your work, attach the following
|
|
182
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
+
replaced with your own identifying information. (Don't include
|
|
184
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
+
comment syntax for the file format. We also recommend that a
|
|
186
|
+
file or class name and description of purpose be included on the
|
|
187
|
+
same "printed page" as the copyright notice for easier
|
|
188
|
+
identification within third-party archives.
|
|
189
|
+
|
|
190
|
+
Copyright [yyyy] [name of copyright owner]
|
|
191
|
+
|
|
192
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
+
you may not use this file except in compliance with the License.
|
|
194
|
+
You may obtain a copy of the License at
|
|
195
|
+
|
|
196
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
+
|
|
198
|
+
Unless required by applicable law or agreed to in writing, software
|
|
199
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
+
See the License for the specific language governing permissions and
|
|
202
|
+
limitations under the License.
|
portallib-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: portallib
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Generate portable task-specific LoRA adapters across language models
|
|
5
|
+
Project-URL: Homepage, https://github.com/ramp-public/portallib
|
|
6
|
+
Project-URL: Repository, https://github.com/ramp-public/portallib
|
|
7
|
+
Project-URL: Documentation, https://github.com/ramp-public/portallib#readme
|
|
8
|
+
Project-URL: Issues, https://github.com/ramp-public/portallib/issues
|
|
9
|
+
Project-URL: Announcement, https://x.com/RampLabs/status/2072381992285647280
|
|
10
|
+
Project-URL: Download, https://pypi.org/project/portallib/
|
|
11
|
+
Author-email: Benjamin Geist <benjamin.geist@ramp.com>
|
|
12
|
+
License-Expression: Apache-2.0
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Keywords: adapters,llm,lora,machine-learning,peft
|
|
15
|
+
Classifier: Development Status :: 3 - Alpha
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Intended Audience :: Science/Research
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Requires-Dist: huggingface-hub<2,>=0.30
|
|
24
|
+
Requires-Dist: peft<1,>=0.15
|
|
25
|
+
Requires-Dist: safetensors<1,>=0.4
|
|
26
|
+
Requires-Dist: torch>=2.2
|
|
27
|
+
Provides-Extra: training
|
|
28
|
+
Requires-Dist: datasets<5,>=3; extra == 'training'
|
|
29
|
+
Requires-Dist: transformers<6,>=4.52; extra == 'training'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# PorTAL: Portable Task Adapters for LLMs
|
|
33
|
+
|
|
34
|
+
<p align="center">
|
|
35
|
+
<picture>
|
|
36
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ramp-public/portallib/main/docs/assets/portal_header_dark_v2.png">
|
|
37
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/ramp-public/portallib/main/docs/assets/portal_header_light_v3.png">
|
|
38
|
+
<img src="https://raw.githubusercontent.com/ramp-public/portallib/main/docs/assets/portal_header_light_v3.png" width="560" alt="PorTAL wordmark passing through two portals">
|
|
39
|
+
</picture>
|
|
40
|
+
</p>
|
|
41
|
+
|
|
42
|
+
> Alpha research release [announced by Ramp Labs](https://x.com/RampLabs/status/2072381992285647280).
|
|
43
|
+
> APIs and artifact schemas may evolve before the first stable release.
|
|
44
|
+
|
|
45
|
+
PorTAL learns a base-agnostic task latent and a light per-base decoder that generates ordinary
|
|
46
|
+
per-layer LoRA weights. A task can be trained once, adapted to supported frozen base models, and
|
|
47
|
+
exported as a standard Hugging Face PEFT adapter.
|
|
48
|
+
|
|
49
|
+
`portallib` is an alpha Python library for loading, training, saving, publishing, and exporting
|
|
50
|
+
PorTAL artifacts with standard PyTorch and Hugging Face interfaces.
|
|
51
|
+
|
|
52
|
+
The included pinned recipes reproduce the PorTAL source-training, target-refitting, and evaluation
|
|
53
|
+
method described by Ramp Labs. Reported results should be generated from the released artifacts and
|
|
54
|
+
their recorded evaluation configuration rather than treated as fixed package guarantees.
|
|
55
|
+
|
|
56
|
+

|
|
57
|
+
|
|
58
|
+
During source training, PorTAL jointly learns the task-latent table, one shared canonical core, and
|
|
59
|
+
one alignment for each source base. To port the learned tasks, it freezes the latent table and core
|
|
60
|
+
and refits only a fresh alignment for the target base. The resulting task adapter is exportable as
|
|
61
|
+
an ordinary PEFT LoRA adapter.
|
|
62
|
+
|
|
63
|
+
## Install
|
|
64
|
+
|
|
65
|
+
Install the inference library from PyPI:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pip install portallib
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Install the optional Hugging Face model and dataset dependencies for training:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pip install 'portallib[training]'
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Python 3.11 and 3.12 are supported. Install a CUDA-compatible PyTorch build for GPU training before
|
|
78
|
+
installing the training extra when your platform requires a specific CUDA wheel.
|
|
79
|
+
|
|
80
|
+
## Load and export
|
|
81
|
+
|
|
82
|
+
Load a native PorTAL artifact, select a trained task, and obtain a normal PEFT model:
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from transformers import AutoModelForCausalLM
|
|
86
|
+
from portallib import PortalModel
|
|
87
|
+
|
|
88
|
+
base = AutoModelForCausalLM.from_pretrained(
|
|
89
|
+
"Qwen/Qwen3-4B",
|
|
90
|
+
revision="1cfa9a7208912126459214e8b04321603b3df60c",
|
|
91
|
+
)
|
|
92
|
+
portal = PortalModel.from_pretrained(
|
|
93
|
+
"RampPublic/portal-qwen3-4b",
|
|
94
|
+
revision="v0.1.0",
|
|
95
|
+
base_model=base,
|
|
96
|
+
)
|
|
97
|
+
model = portal.get_peft_model("rte")
|
|
98
|
+
model.save_pretrained("./portal-rte-qwen3-4b")
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
A task can also be exported without loading the base LLM:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
portal.export_peft("rte", "./portal-rte-qwen3-4b")
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The exported directory is an ordinary PEFT adapter and reloads with
|
|
108
|
+
`PeftModel.from_pretrained`.
|
|
109
|
+
|
|
110
|
+
## Published artifacts
|
|
111
|
+
|
|
112
|
+
| Artifact | Role |
|
|
113
|
+
|---|---|
|
|
114
|
+
| [`RampPublic/portal-qwen3-1.7b`](https://huggingface.co/RampPublic/portal-qwen3-1.7b) | Jointly trained shared weights plus the 1.7B alignment |
|
|
115
|
+
| [`RampPublic/portal-qwen3-4b`](https://huggingface.co/RampPublic/portal-qwen3-4b) | Jointly trained shared weights plus the 4B alignment |
|
|
116
|
+
| [`RampPublic/portal-qwen3-8b`](https://huggingface.co/RampPublic/portal-qwen3-8b) | 1,000-example-per-task refit |
|
|
117
|
+
| [`RampPublic/portal-gemma-3-4b`](https://huggingface.co/RampPublic/portal-gemma-3-4b) | 1,000-example-per-task cross-family refit |
|
|
118
|
+
|
|
119
|
+
The recipes load the `v0.1.0` artifact revisions. Each repository contains one base-specific native
|
|
120
|
+
PorTAL artifact; task-specific standard PEFT adapters can be generated from it as needed.
|
|
121
|
+
|
|
122
|
+
## Examples
|
|
123
|
+
|
|
124
|
+
[`examples/train_example.py`](https://github.com/ramp-public/portallib/blob/main/examples/train_example.py) is thin orchestration around the public
|
|
125
|
+
canonical trainer APIs. It freezes each base model, jointly learns shared task latents and a canonical
|
|
126
|
+
core with one thin alignment per source base, evaluates epoch zero and every training epoch, restores
|
|
127
|
+
the best held-out epoch, and writes one native artifact per source base. Its only model downloads are
|
|
128
|
+
the raw Hugging Face bases selected for source training.
|
|
129
|
+
|
|
130
|
+
The complete pinned recipe is a short, editable block near the top of the file. It selects the
|
|
131
|
+
dataset, exact model revisions, output directory, source bases, and `PortalTrainingConfig`:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
python examples/train_example.py
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
[`examples/refit_example.py`](https://github.com/ramp-public/portallib/blob/main/examples/refit_example.py) loads either source artifact as a carrier
|
|
138
|
+
for the task vectors and canonical core learned jointly from Qwen3-1.7B and Qwen3-4B. It downloads
|
|
139
|
+
only the new raw target base, freezes the shared components, and trains a fresh target alignment:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
python examples/refit_example.py
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The checked-in recipe reads the shared weights from `RampPublic/portal-qwen3-4b`; this does not make
|
|
146
|
+
the refit 4B-only—the 1.7B and 4B source artifacts contain identical jointly trained task latents and
|
|
147
|
+
canonical core weights. The default target is Qwen3-8B with at most 1,000 training examples per task.
|
|
148
|
+
The adjacent Gemma 3 recipe uses the same shared components and its exact text-decoder layer path.
|
|
149
|
+
|
|
150
|
+
[`examples/evaluate_example.py`](https://github.com/ramp-public/portallib/blob/main/examples/evaluate_example.py) loads a trained PorTAL artifact and
|
|
151
|
+
its matching raw base, then reports the base floor, adapted per-task metrics, macro metrics, and
|
|
152
|
+
accuracy lift:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
python examples/evaluate_example.py
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
The checked-in evaluation recipe uses `RampPublic/portal-qwen3-8b`; change the artifact and matching
|
|
159
|
+
base recipe together to evaluate one of the other published source or refit artifacts.
|
|
160
|
+
|
|
161
|
+
The examples are repository assets rather than installed console commands. Clone the repository to
|
|
162
|
+
run them, then install the released training package:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
git clone https://github.com/ramp-public/portallib
|
|
166
|
+
cd portallib
|
|
167
|
+
pip install 'portallib[training]==0.1.0'
|
|
168
|
+
python examples/train_example.py
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
[`REPRODUCING.md`](https://github.com/ramp-public/portallib/blob/main/REPRODUCING.md) records pinned dataset and model revisions, the complete training
|
|
172
|
+
configuration, checkpoint selection, and source/Qwen/Gemma recipes.
|
|
173
|
+
|
|
174
|
+
[`COMPUTE.md`](https://github.com/ramp-public/portallib/blob/main/COMPUTE.md) shows how to run any example locally with Docker or remotely through
|
|
175
|
+
Modal. The compute wrapper provisions the runtime and persistent storage; the training and evaluation
|
|
176
|
+
behavior comes from the installed `portallib` release and selected recipe.
|
|
177
|
+
|
|
178
|
+
## Model compatibility
|
|
179
|
+
|
|
180
|
+
PorTAL supports Qwen3 and cross-family refitting to Gemma 3. Qwen3 exposes decoder layers at
|
|
181
|
+
`model.layers`; Gemma 3 exposes its text decoder at
|
|
182
|
+
`model.language_model.layers`. The default projection paths cover the usual query, key, value,
|
|
183
|
+
attention-output, and gated-MLP linear modules used by those families.
|
|
184
|
+
|
|
185
|
+
Other causal language-model families are expected to work when they expose uniform linear
|
|
186
|
+
projections across decoder layers. Pass their exact layer and projection paths through `PortalBase`;
|
|
187
|
+
PorTAL validates every configured path and dimension before training. Automatic architecture
|
|
188
|
+
adapters and models with non-uniform per-layer projection dimensions are not yet part of the
|
|
189
|
+
supported v0.1 compatibility surface. Contributions that add exact, tested architecture mappings
|
|
190
|
+
are welcome.
|
|
191
|
+
|
|
192
|
+
For another model family, set its exact `BaseRecipe.layer_path`; paths are explicit rather than
|
|
193
|
+
inferred from module-name patterns, so an incompatible model fails before training.
|
|
194
|
+
|
|
195
|
+
The checked-in `modules=("q", "v")` setting generates LoRA for query/value projections. Set it to
|
|
196
|
+
`("q", "k", "v", "o", "gate", "up", "down")` to include the attention output and MLP
|
|
197
|
+
projections. In both cases, the base model parameters remain frozen.
|
|
198
|
+
|
|
199
|
+
## Artifact format
|
|
200
|
+
|
|
201
|
+
Native artifacts use the standard Hugging Face layout:
|
|
202
|
+
|
|
203
|
+
- `config.json` contains the schema version, base model and revision, task names, LoRA settings,
|
|
204
|
+
exact layer/module paths, and projection dimensions.
|
|
205
|
+
- `model.safetensors` contains `task_latents`, the canonical `core`, and one base-specific
|
|
206
|
+
`alignment`, with `portallib` format metadata.
|
|
207
|
+
- `README.md` is the generated model card.
|
|
208
|
+
|
|
209
|
+
`PortalModel` inherits `ModelHubMixin`, so `save_pretrained`, `from_pretrained`, and `push_to_hub`
|
|
210
|
+
follow standard Hugging Face Hub behavior:
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
portal.push_to_hub("your-namespace/portal-qwen3-4b", private=True)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Configured layers and projections are resolved deterministically. Missing modules, incompatible
|
|
217
|
+
dimensions, unknown schema versions, and inconsistent target declarations fail explicitly.
|
|
218
|
+
|
|
219
|
+
## Public API
|
|
220
|
+
|
|
221
|
+
- `PortalConfig` validates artifacts and builds exact configurations from supported base models.
|
|
222
|
+
- `PortalCoreTrainer` jointly trains shared latents/core and one alignment per source base using
|
|
223
|
+
balanced per-task updates, EMA loss normalization, and per-base latent-gradient balancing.
|
|
224
|
+
- `PortalAdapterRefitter` freezes a source artifact's latents/core and trains only a target alignment.
|
|
225
|
+
- `PortalTrainingConfig.from_portal_config` preserves an artifact's architecture while selecting a
|
|
226
|
+
new optimization recipe for refitting.
|
|
227
|
+
- `PortalEvaluator` batches candidate continuations while reporting character-normalized
|
|
228
|
+
multiple-choice accuracy and token-mean gold NLL.
|
|
229
|
+
- `EvaluationResult.to_dict` returns the canonical JSON-ready evaluation representation.
|
|
230
|
+
- `PortalDecoder` combines a canonical core and one base-specific alignment to generate LoRA factors.
|
|
231
|
+
- `PortalModel` loads, saves, publishes, materializes, and exports trained artifacts.
|
|
232
|
+
- `ChoiceDataset` loads and saves the normalized local/Hub task schema and supports explicit Hub upload.
|
|
233
|
+
- `collate_gold_batch` provides the causal-LM batch format used by the training APIs.
|
|
234
|
+
|
|
235
|
+
## Development
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
uv run ruff check src tests examples scripts
|
|
239
|
+
uv run pytest -q
|
|
240
|
+
uv run python -m build
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
PorTAL is licensed under Apache-2.0.
|
|
244
|
+
|
|
245
|
+
## Citation
|
|
246
|
+
|
|
247
|
+
If you use PorTAL, cite the software metadata in
|
|
248
|
+
[`CITATION.cff`](https://github.com/ramp-public/portallib/blob/main/CITATION.cff).
|