pixr 0.1.0.dev0__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.
- pixr-0.1.0.dev0/LICENSE +201 -0
- pixr-0.1.0.dev0/PKG-INFO +349 -0
- pixr-0.1.0.dev0/README.md +311 -0
- pixr-0.1.0.dev0/pyproject.toml +73 -0
- pixr-0.1.0.dev0/src/pixr/__init__.py +3 -0
- pixr-0.1.0.dev0/src/pixr/app/__init__.py +0 -0
- pixr-0.1.0.dev0/src/pixr/app/eval.py +95 -0
- pixr-0.1.0.dev0/src/pixr/app/train.py +192 -0
- pixr-0.1.0.dev0/src/pixr/data/__init__.py +2 -0
- pixr-0.1.0.dev0/src/pixr/data/loader.py +26 -0
- pixr-0.1.0.dev0/src/pixr/data/transforms.py +52 -0
- pixr-0.1.0.dev0/src/pixr/framework/__init__.py +7 -0
- pixr-0.1.0.dev0/src/pixr/framework/config.py +79 -0
- pixr-0.1.0.dev0/src/pixr/framework/device.py +176 -0
- pixr-0.1.0.dev0/src/pixr/framework/ema.py +85 -0
- pixr-0.1.0.dev0/src/pixr/framework/logger.py +32 -0
- pixr-0.1.0.dev0/src/pixr/framework/monitor.py +276 -0
- pixr-0.1.0.dev0/src/pixr/framework/random.py +15 -0
- pixr-0.1.0.dev0/src/pixr/framework/task.py +369 -0
- pixr-0.1.0.dev0/src/pixr/framework/trainer.py +397 -0
- pixr-0.1.0.dev0/src/pixr/generation.py +242 -0
- pixr-0.1.0.dev0/src/pixr/loss.py +128 -0
- pixr-0.1.0.dev0/src/pixr/models/__init__.py +11 -0
- pixr-0.1.0.dev0/src/pixr/models/attention.py +178 -0
- pixr-0.1.0.dev0/src/pixr/models/config.py +239 -0
- pixr-0.1.0.dev0/src/pixr/models/configs/cronut_b16_tiktoken.json +34 -0
- pixr-0.1.0.dev0/src/pixr/models/configs/cronut_s16_tiktoken.json +34 -0
- pixr-0.1.0.dev0/src/pixr/models/configs/cruller_hybrid_r50_base_1280.json +17 -0
- pixr-0.1.0.dev0/src/pixr/models/configs/cruller_naflex_clip_base.json +30 -0
- pixr-0.1.0.dev0/src/pixr/models/configs/cruller_naflex_clip_base_8k.json +30 -0
- pixr-0.1.0.dev0/src/pixr/models/configs/cruller_naflex_clip_base_ettin150m.json +31 -0
- pixr-0.1.0.dev0/src/pixr/models/configs/cruller_naflex_clip_large.json +30 -0
- pixr-0.1.0.dev0/src/pixr/models/configs/cruller_naflex_clip_large_ettin400m.json +31 -0
- pixr-0.1.0.dev0/src/pixr/models/configs/cruller_naflex_siglip2_base.json +14 -0
- pixr-0.1.0.dev0/src/pixr/models/configs/cruller_naflex_siglip2_base_ettin150m.json +15 -0
- pixr-0.1.0.dev0/src/pixr/models/configs/cruller_naflex_siglip2_base_qwen3_0.6b.json +16 -0
- pixr-0.1.0.dev0/src/pixr/models/configs/cruller_naflex_siglip2_so400m.json +14 -0
- pixr-0.1.0.dev0/src/pixr/models/configs/cruller_vit_clip_base_1280.json +20 -0
- pixr-0.1.0.dev0/src/pixr/models/configs/fritter_naflex_siglip2_base_ettin150m.json +18 -0
- pixr-0.1.0.dev0/src/pixr/models/configs/fritter_naflex_siglip2_base_ettin400m.json +18 -0
- pixr-0.1.0.dev0/src/pixr/models/configs/fritter_naflex_siglip2_base_qwen3_0.6b.json +18 -0
- pixr-0.1.0.dev0/src/pixr/models/configs/fritter_naflex_siglip2_so400m_ettin1b.json +18 -0
- pixr-0.1.0.dev0/src/pixr/models/cronut.py +389 -0
- pixr-0.1.0.dev0/src/pixr/models/cruller.py +124 -0
- pixr-0.1.0.dev0/src/pixr/models/factory.py +79 -0
- pixr-0.1.0.dev0/src/pixr/models/fritter.py +198 -0
- pixr-0.1.0.dev0/src/pixr/models/image_encoder_timm.py +181 -0
- pixr-0.1.0.dev0/src/pixr/models/kv_cache.py +112 -0
- pixr-0.1.0.dev0/src/pixr/models/param_groups.py +76 -0
- pixr-0.1.0.dev0/src/pixr/models/text_decoder.py +433 -0
- pixr-0.1.0.dev0/src/pixr/models/text_decoder_ettin.py +436 -0
- pixr-0.1.0.dev0/src/pixr/models/text_decoder_qwen3.py +352 -0
- pixr-0.1.0.dev0/src/pixr/task/__init__.py +4 -0
- pixr-0.1.0.dev0/src/pixr/task/common.py +212 -0
- pixr-0.1.0.dev0/src/pixr/task/docvqa.py +94 -0
- pixr-0.1.0.dev0/src/pixr/task/read.py +140 -0
- pixr-0.1.0.dev0/src/pixr/task/task_registry.py +19 -0
- pixr-0.1.0.dev0/src/pixr/tokenizers/__init__.py +3 -0
- pixr-0.1.0.dev0/src/pixr/tokenizers/config.py +8 -0
- pixr-0.1.0.dev0/src/pixr/tokenizers/tiktoken_tokenizer.py +152 -0
- pixr-0.1.0.dev0/src/pixr/tokenizers/tokenizer.py +45 -0
- pixr-0.1.0.dev0/src/pixr/utils/__init__.py +3 -0
- pixr-0.1.0.dev0/src/pixr/utils/cli.py +110 -0
- pixr-0.1.0.dev0/src/pixr/utils/file_utils.py +36 -0
- pixr-0.1.0.dev0/src/pixr/utils/json_utils.py +317 -0
- pixr-0.1.0.dev0/src/pixr/utils/metrics.py +65 -0
- pixr-0.1.0.dev0/src/pixr/utils/name_utils.py +11 -0
- pixr-0.1.0.dev0/src/pixr/version.py +1 -0
- pixr-0.1.0.dev0/tests/test_app_cfg.py +44 -0
- pixr-0.1.0.dev0/tests/test_distributed.py +166 -0
- pixr-0.1.0.dev0/tests/test_loss.py +74 -0
- pixr-0.1.0.dev0/tests/test_metrics.py +13 -0
- pixr-0.1.0.dev0/tests/test_models.py +725 -0
pixr-0.1.0.dev0/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright 2024 Hugging Face Inc.
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
pixr-0.1.0.dev0/PKG-INFO
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pixr
|
|
3
|
+
Version: 0.1.0.dev0
|
|
4
|
+
Summary: Pixel Reading: OCR-free document understanding models (image encoder + text decoder), training and evaluation
|
|
5
|
+
Keywords: document-ai,ocr-free,document-understanding,vision-language,docvqa,pytorch
|
|
6
|
+
Author-Email: Ross Wightman <rwightman@gmail.com>
|
|
7
|
+
License-Expression: Apache-2.0
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Education
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Image Recognition
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Project-URL: homepage, https://github.com/rwightman/pixr
|
|
19
|
+
Project-URL: repository, https://github.com/rwightman/pixr
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Requires-Dist: torch>=2.8
|
|
22
|
+
Requires-Dist: timm>=1.0.31
|
|
23
|
+
Requires-Dist: transformers
|
|
24
|
+
Requires-Dist: huggingface_hub
|
|
25
|
+
Requires-Dist: safetensors
|
|
26
|
+
Requires-Dist: fsspec
|
|
27
|
+
Requires-Dist: numpy
|
|
28
|
+
Requires-Dist: chugr>=0.2.0.dev0
|
|
29
|
+
Requires-Dist: Levenshtein
|
|
30
|
+
Requires-Dist: pyyaml
|
|
31
|
+
Requires-Dist: jsonargparse
|
|
32
|
+
Requires-Dist: tiktoken
|
|
33
|
+
Provides-Extra: wandb
|
|
34
|
+
Requires-Dist: wandb; extra == "wandb"
|
|
35
|
+
Provides-Extra: tensorboard
|
|
36
|
+
Requires-Dist: tensorboard; extra == "tensorboard"
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
|
|
39
|
+
# Pixel Reading (`pixr`)
|
|
40
|
+
|
|
41
|
+
OCR-free, end-to-end document understanding models trained on open data: pixels in, text out. `pixr` covers the
|
|
42
|
+
models (image encoder + text decoder families), the training tasks (page reading pretraining, DocVQA fine-tuning),
|
|
43
|
+
generation (KV cached greedy / beam search) and a lightweight PyTorch training framework (DDP / FSDP2, compile, EMA).
|
|
44
|
+
Data pipelines are provided by [`chugr`](https://github.com/rwightman/chugr).
|
|
45
|
+
|
|
46
|
+
`pixr` is the continuation of the original `pixparse` project (huggingface/pixparse, 2023), renamed and revived.
|
|
47
|
+
|
|
48
|
+
## Status
|
|
49
|
+
|
|
50
|
+
Alpha, expect breaking changes. The current focus is reproducing decent OCR / DocVQA results w/ open data and modern
|
|
51
|
+
(NaFlex, native aspect ratio) image encoders.
|
|
52
|
+
|
|
53
|
+
### Changes since `pixparse`
|
|
54
|
+
|
|
55
|
+
* Ported to `chugr` 0.2, NaFlexVit (native aspect / variable resolution) image encoders, and self-contained text
|
|
56
|
+
decoders (BART, Ettin, Qwen3) w/ three model families (see below)
|
|
57
|
+
* FSDP2, torch.compile, EMA, NaFlex batching, chunked LM loss, KV cached greedy / beam search generation
|
|
58
|
+
* Fixes for issues that hampered the original DocVQA results:
|
|
59
|
+
* DocVQA fine-tune loss was applied to question + answer tokens (prompt masking used the task start token)
|
|
60
|
+
* train / eval image preprocessing mismatched (aspect preserving resize + pad vs stretch, long axis rotation)
|
|
61
|
+
* DocVQA eval decoded by re-tokenizing the generated string each step (BPE round trip is not idempotent)
|
|
62
|
+
* `scale_embedding` was forced on for BART decoders (copied from Donut's mBART, BART is trained w/o)
|
|
63
|
+
* `ModelArgs` command line overrides (image size, etc) were silently dropped
|
|
64
|
+
* pretrained BART cross-attention weights significantly slow learning w/ an image encoder, cross-attention is now
|
|
65
|
+
re-initialized w/ zero init output projections by default (decoder starts as the pretrained LM)
|
|
66
|
+
|
|
67
|
+
## Installation
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
pip install --pre pixr # pulls in chugr
|
|
71
|
+
pip install --pre "pixr[wandb]" # optional logging extras: wandb, tensorboard
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
NOTE the NaFlexVit attention backends (`attn_backend`) and pretrained patch embedding channel adaptation used by the
|
|
75
|
+
NaFlex models need `timm` changes that are not in a release yet, until they are, install `timm` from source w/ them.
|
|
76
|
+
|
|
77
|
+
From a source checkout (the training / eval scripts and the test launcher live in the repository):
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
pip install -e ./chugr -e ./pixr
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Models
|
|
84
|
+
|
|
85
|
+
Three model families share the same tasks, data pipelines, loss masking and (greedy / beam search, KV cached) generation:
|
|
86
|
+
|
|
87
|
+
* **Cruller** -- image encoder + autoregressive text decoder w/ cross-attention (Donut style)
|
|
88
|
+
* **Fritter** -- image encoder -> (optional m x m token merge) -> projector -> image token prefix for a decoder-only
|
|
89
|
+
LM w/ prefix-LM attention (PaLI / LLaVA style)
|
|
90
|
+
* **Cronut** -- native decoder-only transformer over image patches and text (GenLIP style single trunk w/ 2D/1D
|
|
91
|
+
interleaved MRoPE, qk-norm, gated attention, SwiGLU), trained from scratch w/ a tiktoken tokenizer
|
|
92
|
+
|
|
93
|
+
Model configs live in `src/pixr/models/configs`:
|
|
94
|
+
|
|
95
|
+
| config | image encoder | text decoder |
|
|
96
|
+
|---|---|---|
|
|
97
|
+
| `cruller_naflex_clip_base` | NaFlexVit B/16, CLIP style (pre-norm, cls token), OpenAI CLIP init, 4096 patches | BART base (6L) |
|
|
98
|
+
| `cruller_naflex_clip_base_8k` | as above, 8192 patches | BART base (6L) |
|
|
99
|
+
| `cruller_naflex_clip_base_ettin150m` | as above, 4096 patches | Ettin (ModernBERT) decoder 150M + cross-attn |
|
|
100
|
+
| `cruller_naflex_siglip2_base` | NaFlexVit B/16 SigLIP2 | BART base (6L) |
|
|
101
|
+
| `cruller_naflex_clip_large` | NaFlexVit L/14 CLIP style, OpenAI CLIP init, 6144 patches | BART large (8L) |
|
|
102
|
+
| `cruller_naflex_clip_large_ettin400m` | as above | Ettin decoder 400M + cross-attn |
|
|
103
|
+
| `cruller_naflex_siglip2_base_ettin150m` | NaFlexVit B/16 SigLIP2 | Ettin decoder 150M + cross-attn |
|
|
104
|
+
| `cruller_naflex_siglip2_so400m` | NaFlexVit SO400M/16 SigLIP2 | BART large (8L) |
|
|
105
|
+
| `fritter_naflex_siglip2_base_ettin150m` | NaFlexVit B/16 SigLIP2, 2x2 token merge | Ettin decoder 150M (prefix-LM) |
|
|
106
|
+
| `fritter_naflex_siglip2_base_ettin400m` | as above | Ettin decoder 400M (prefix-LM) |
|
|
107
|
+
| `fritter_naflex_siglip2_so400m_ettin1b` | NaFlexVit SO400M/16 SigLIP2, 2x2 token merge | Ettin decoder 1B (prefix-LM) |
|
|
108
|
+
| `cruller_naflex_siglip2_base_qwen3_0.6b` | NaFlexVit B/16 SigLIP2 | Qwen3 0.6B + zero init cross-attn every N layers |
|
|
109
|
+
| `fritter_naflex_siglip2_base_qwen3_0.6b` | NaFlexVit B/16 SigLIP2, 2x2 token merge | Qwen3 0.6B (prefix-LM) |
|
|
110
|
+
| `cronut_s16_tiktoken` / `cronut_b16_tiktoken` | -- (patch embed in trunk) | -- (single trunk), `cl100k_base` |
|
|
111
|
+
| `cruller_vit_clip_base_1280` | fixed size ViT B/16 CLIP @ 1280x960 | BART base (6L) |
|
|
112
|
+
| `cruller_hybrid_r50_base_1280` | fixed size hybrid R50 + ViT B/16 @ 1280x960 | BART base (6L) |
|
|
113
|
+
|
|
114
|
+
NaFlex models consume pages at their native aspect ratio, resized to fit a patch budget (`--task.model.max-seq-len`),
|
|
115
|
+
the budget can be changed between pretraining and fine-tuning.
|
|
116
|
+
|
|
117
|
+
Ettin (ModernBERT) decoders use 64 token sliding window attention in 2 of every 3 layers, a poor fit for a long
|
|
118
|
+
image prefix (Fritter), Qwen3 (full attention) is the recommended prefix-LM decoder.
|
|
119
|
+
|
|
120
|
+
### Attention backends
|
|
121
|
+
|
|
122
|
+
Padded NaFlex sequences can use a dense mask or a variable length kernel, selected per model config field:
|
|
123
|
+
|
|
124
|
+
| field | options |
|
|
125
|
+
|---|---|
|
|
126
|
+
| `image_encoder.attn_backend` | `sdpa` (dense mask), `varlen` (packed, CUDA), `flex` (FlexAttention block mask), batches w/o padding skip masking for all -- requires the timm `naflex-attn-backends` branch |
|
|
127
|
+
| `text_decoder.cross_attn_backend` | `sdpa`, `varlen`, `flex` |
|
|
128
|
+
| `text_decoder.self_attn_backend` | `sdpa` (dense prefix-LM mask), `flex` (prefix-LM block mask), Ettin / Qwen3 |
|
|
129
|
+
| `cronut.attn_backend` | `sdpa`, `flex` |
|
|
130
|
+
|
|
131
|
+
Override from the command line w/ `--task.model.image-attn-backend`, `--task.model.cross-attn-backend`, and
|
|
132
|
+
`--task.model.self-attn-backend` (decoder self-attention, or the Cronut trunk), e.g. `--task.model.image-attn-backend flex`.
|
|
133
|
+
|
|
134
|
+
### Tokenizers
|
|
135
|
+
|
|
136
|
+
HF tokenizers by name (`facebook/bart-base`, `Qwen/Qwen3-0.6B`, ...) or tiktoken encodings via `tiktoken:<encoding>`
|
|
137
|
+
(`tiktoken:cl100k_base`, `tiktoken:o200k_base`, ...), w/ eos / pad / bos and task tokens appended above the base vocab.
|
|
138
|
+
|
|
139
|
+
## Usage
|
|
140
|
+
|
|
141
|
+
### Training / evaluation apps
|
|
142
|
+
|
|
143
|
+
The apps are installed as `pixr-train` / `pixr-eval` (or `python -m pixr.app.train` / `python -m pixr.app.eval`).
|
|
144
|
+
Distributed runs use `torchrun` (or `python -m torch.distributed.run`):
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
torchrun --nproc_per_node 2 -m pixr.app.train --task read --task.model.name cruller_naflex_siglip2_base \
|
|
148
|
+
--train-data.source "<idl-wds shards>" --train-data.num-samples 200000 --trainer.num-intervals 40 ...
|
|
149
|
+
pixr-eval --task docvqa --checkpoint-path <checkpoint.pt> \
|
|
150
|
+
--eval-data.source pixparse/docvqa-single-page-questions --eval-data.split validation --eval-data.format hfds
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Scripts in `scripts/` (source checkout) cover the main workflow w/ tuned defaults, see each script for env var options:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# 1. pretrain (read all text on a page) on IDL, streamed from the HF hub
|
|
157
|
+
NUM_GPUS=2 MODEL=cruller_naflex_siglip2_base ./scripts/pretrain_idl.sh
|
|
158
|
+
|
|
159
|
+
# held out reading CER / WER
|
|
160
|
+
CHECKPOINT=output/pretrain_cruller_naflex_siglip2_base_idl/checkpoints/checkpoint-latest.pt ./scripts/eval_ocr.sh
|
|
161
|
+
|
|
162
|
+
# 2. fine-tune on DocVQA (ANLS on validation each eval interval)
|
|
163
|
+
CHECKPOINT=output/pretrain_cruller_naflex_siglip2_base_idl/checkpoints/checkpoint-latest.pt ./scripts/finetune_docvqa.sh
|
|
164
|
+
|
|
165
|
+
# 3. evaluate (validation ANLS, or SPLIT=test for an eval server submission file)
|
|
166
|
+
CHECKPOINT=output/finetune_docvqa/checkpoints/checkpoint-latest.pt ./scripts/eval_docvqa.sh
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Command line / config
|
|
170
|
+
|
|
171
|
+
Apps are configured by dataclasses parsed w/ [jsonargparse](https://github.com/omni-us/jsonargparse):
|
|
172
|
+
|
|
173
|
+
* `--task read|docvqa` selects the task (and the type of the `task` config section), default `read` for train
|
|
174
|
+
* nested fields map to dotted args, written w/ dashes: `--trainer.opt.learning-rate 1e-4` (underscores also accepted)
|
|
175
|
+
* `--task.*` -- task: model, tokenizer, image transforms, dtype / amp, max text length, eval generation
|
|
176
|
+
* `--trainer.*` -- optimization: intervals, warmup, optimizer / schedule (`--trainer.opt.*`), EMA, compile, grad ckpt,
|
|
177
|
+
FSDP
|
|
178
|
+
* `--train-data.*` / `--eval-data.*` -- chugr data args (source, format, split, batch size, workers, NaFlex batching)
|
|
179
|
+
* `--config file.yaml` loads a config (CLI args override), `--print-config` dumps the resolved config, `--help` lists all
|
|
180
|
+
* lists are passed as `--train-data.naflex-seq-lens [1024,2048,4096]`
|
|
181
|
+
|
|
182
|
+
The full resolved config is written to `<output_dir>/<experiment>/config.yaml` and can be passed back via `--config`.
|
|
183
|
+
|
|
184
|
+
### Distributed / compile
|
|
185
|
+
|
|
186
|
+
Distributed runs (`torch.distributed.run`) use DDP by default, `--trainer.fsdp true` shards params, grads and
|
|
187
|
+
optimizer state w/ FSDP2 (`fully_shard` per encoder block / decoder layer + root, models list their blocks in
|
|
188
|
+
`fsdp_shard_modules()`). The handling follows the OpenCLIP `TrainingTask` (`prepare_distributed` / `prepare_fsdp` /
|
|
189
|
+
`compile` on the task):
|
|
190
|
+
|
|
191
|
+
* FSDP mixed precision is a `MixedPrecisionPolicy` (bf16 params, fp32 gradient reduction), autocast is suppressed
|
|
192
|
+
* `--trainer.grad-checkpointing` w/ FSDP applies composable activation checkpointing per block (inline otherwise)
|
|
193
|
+
* `--trainer.compile true --trainer.compile-strategy task|model|blocks`: `task` compiles the task training forward
|
|
194
|
+
(model + loss), `model` the model before DDP, `blocks` the blocks in place before DDP (checkpoint recompute stays
|
|
195
|
+
in eager autograd, bounding compiled backward memory). W/ FSDP, blocks are always compiled inside `prepare_fsdp()`,
|
|
196
|
+
ordered compile -> composable checkpointing -> `fully_shard` (checkpoint hooks on the compiled wrapper so recompute
|
|
197
|
+
re-enters the FSDP all-gather hooks), `--compile-mode` / `--compile-dynamic` / `--compile-backend` pass through
|
|
198
|
+
* eval and train metrics run w/ the params gathered (`task.full_params()`), so ranks decode independently
|
|
199
|
+
* checkpoints are gathered full state dicts (model, EMA, optimizer), loadable w/o FSDP, model / EMA weights are
|
|
200
|
+
interchangeable between FSDP and DDP runs (optimizer state is not)
|
|
201
|
+
|
|
202
|
+
`scripts/check_distributed.py` checks single / DDP / FSDP parity (loss trajectories, final params), grad
|
|
203
|
+
checkpointing, accumulation, compile, EMA, resume and generation through the Trainer on synthetic batches.
|
|
204
|
+
|
|
205
|
+
### Generation
|
|
206
|
+
|
|
207
|
+
`pixr.generation` provides batched, KV cached greedy (`generate_greedy`) and beam search (`generate_beam`) decoding,
|
|
208
|
+
`--task.eval-num-beams` selects beam search for eval. Cruller, Fritter and Cronut share one incremental decoding
|
|
209
|
+
interface:
|
|
210
|
+
|
|
211
|
+
```python
|
|
212
|
+
memory = model.encode_image(image_input) # per image, computed once
|
|
213
|
+
logits, state = model.prefill(memory, prompt_ids, prompt_mask) # left padded prompts
|
|
214
|
+
logits, state = model.step(token_ids, state) # one token per hypothesis
|
|
215
|
+
state.reorder(parent_idx) # select / duplicate hypotheses (beam search)
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
The per image memory and the per hypothesis sequence state are separate (`pixr/models/kv_cache.py`). Cruller's
|
|
219
|
+
cross-attention K / V are projected once inside each decoder layer and shared by all hypotheses of an image (several
|
|
220
|
+
prompts or beams per image, image-major order), only the self-attention caches are reordered. Under FSDP, generation
|
|
221
|
+
must run inside `task.full_params()` (ranks then decode independently).
|
|
222
|
+
|
|
223
|
+
### LR scaling
|
|
224
|
+
|
|
225
|
+
Params are grouped by component via the model's `param_layer_map()`: `encoder` (image encoder), `bridge`
|
|
226
|
+
(cross-attention / prefix projector), `decoder` (text decoder / LM trunk). Each has an LR multiplier
|
|
227
|
+
(`--trainer.opt.encoder-lr-scale`, `--trainer.opt.bridge-lr-scale`, `--trainer.opt.decoder-lr-scale`) and the
|
|
228
|
+
encoder / decoder support layer-wise LR decay (`--trainer.opt.encoder-layer-decay 0.75`,
|
|
229
|
+
`--trainer.opt.decoder-layer-decay`). `--trainer.opt.lr-scale-overrides '{"embed_tokens": 2.0}'` adds multipliers
|
|
230
|
+
by param name regex. Training pretrained encoders at full LR from the start wrecks their features before the decoder
|
|
231
|
+
learns to use them (reading never takes off), `scripts/pretrain_idl.sh` uses `ENC_LR_SCALE=0.1`.
|
|
232
|
+
|
|
233
|
+
### LM loss
|
|
234
|
+
|
|
235
|
+
The LM head + cross-entropy is fused and chunked over tokens by default (`--task.loss-chunk-size 4096`, 0 to
|
|
236
|
+
materialize full logits), padding is dropped before the head GEMM and each chunk's logits are recomputed in backward,
|
|
237
|
+
so the [tokens, vocab] logits (~150k vocab for Qwen3) are never materialized. `--task.z-loss-weight` (e.g. `1e-4`) adds
|
|
238
|
+
a z-loss (mean squared logsumexp), `--task.label-smoothing` is supported by both paths.
|
|
239
|
+
|
|
240
|
+
### NaFlex batching
|
|
241
|
+
|
|
242
|
+
For NaFlex models the train loader can draw a sequence length per batch and size the batch to a token budget, w/
|
|
243
|
+
samples resized to the batch's patch budget (rank-identical schedule, from OpenCLIP's streaming NaFlex loader):
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
--train-data.naflex-seq-lens [1024,2048,4096] --train-data.naflex-seq-len-probs [0.25,0.25,0.5] \
|
|
247
|
+
--train-data.naflex-max-tokens 65536 --train-data.naflex-text-tokens 512 --trainer.opt.loss-batch-scale sqrt
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
`--train-data.length-bucketing true` groups samples of similar target text length. Neither requires resampled shards.
|
|
251
|
+
|
|
252
|
+
Checkpoints include the resolved model config and the tokens added to the tokenizer, so fine-tuning and evaluation
|
|
253
|
+
only need `--checkpoint-path`, task tokens are appended and their embeddings initialized from the mean embedding.
|
|
254
|
+
|
|
255
|
+
## Code Organization
|
|
256
|
+
|
|
257
|
+
Within `src/pixr`:
|
|
258
|
+
* `app/` - CLI applications for training and evaluation
|
|
259
|
+
* `app/train.py` - main training CLI entrypoint, will attempt to keep useable across tasks
|
|
260
|
+
* `app/eval.py` - main evaluation CLI entrypoint
|
|
261
|
+
* `data/` - data loaders, image and text preprocessing
|
|
262
|
+
* `framework/` - lightweight train & evaluation scaffolding on top of canonical PyTorch
|
|
263
|
+
* `framework/task.py` - `TrainingTask` base (model + objective + eval)
|
|
264
|
+
* `framework/trainer.py` - `Trainer` (optimizer, LR schedule, AMP, grad accumulation, DDP / FSDP2 / compile setup,
|
|
265
|
+
EMA, train state)
|
|
266
|
+
* `models/` - modelling code with associated factory methods and helpers
|
|
267
|
+
* `task/` - tasks (`read` pretraining, `docvqa` fine-tune), registered in `task/task_registry.py`
|
|
268
|
+
* `tokenizers/` - tokenizer creation and task token handling
|
|
269
|
+
* `generation.py` - batched, KV cached greedy and beam search decoding (`--task.eval-num-beams`)
|
|
270
|
+
* `utils/` - misc utils that don't have a home (`utils/cli.py` -- jsonargparse config / CLI parsing)
|
|
271
|
+
|
|
272
|
+
## Concepts & Terminology
|
|
273
|
+
|
|
274
|
+
Some terms and concepts used in this project that may be a bit unfamiliar.
|
|
275
|
+
|
|
276
|
+
### Task
|
|
277
|
+
A key organization concept in this project. Package the model with its loss, pre/post-processing, and optimization setup together for a given objective.
|
|
278
|
+
|
|
279
|
+
Examples of tasks conceptually:
|
|
280
|
+
* Pretraining a Donut style (image enc + text dec) model on supervised (OCR annotation) doc-text dataset
|
|
281
|
+
* Pretraining a Pix2Struct style (image enc + text dec) model w/ a dataset of webpage/screenshots and structured, simplified HTML
|
|
282
|
+
* Pretraining a PaLI style (image enc + text enc-dec) model w/ prefix & masked-token completion on datasets as above
|
|
283
|
+
* Fine-tuning any of the above pretrained models on a possibly large variety of downstream tasks
|
|
284
|
+
* Semi-structured doc parsing - receipt, invoice, business cards, etc.
|
|
285
|
+
* VQA
|
|
286
|
+
* Captioning
|
|
287
|
+
* ... and more
|
|
288
|
+
|
|
289
|
+
With the Task concept, the data pipeline exists outside the task. The data pipeline is coupled to the task by passing the pre-processing functions created within the task to the data pipeline on creation (`task.train_data_cfg()` / `task.eval_data_cfg()`).
|
|
290
|
+
|
|
291
|
+
A task is a `TrainingTask` (an `nn.Module` wrapping the model) implementing `training_forward(batch) -> (outputs, losses)`,
|
|
292
|
+
optional `train_metrics()`, and `evaluate(loader)`. The generic `Trainer` owns everything else (optimizer, schedule,
|
|
293
|
+
AMP, accumulation, setup ordering for DDP / FSDP2 / compile, EMA, checkpointing state). Tasks are agnostic to the model family.
|
|
294
|
+
|
|
295
|
+
### Interval
|
|
296
|
+
|
|
297
|
+
You'll see the term 'interval' in the code, sometimes next to epoch. It's related, but an epoch means 'one complete pass of the dataset', an interval may be an epoch, but it may not. Interval is a span of training between checkpoints, ideally meaningful enough in duration to warrant evaluating and archiving each interval checkpoint.
|
|
298
|
+
|
|
299
|
+
In OpenCLIP development the term arose when using shard sampling with replacement, where the intervals between checkpoints were determined by limitations on job durations or likelihood of crashes.
|
|
300
|
+
|
|
301
|
+
## Development
|
|
302
|
+
|
|
303
|
+
Tests: `pytest tests` (`tests/test_distributed.py` runs FSDP2 / DDP on a single rank NCCL process group, skipped w/o CUDA).
|
|
304
|
+
|
|
305
|
+
For short test / train / eval runs on two GPUs (source checkout), use the scenario launcher from an environment with editable
|
|
306
|
+
`pixr`, `chugr`, and the local `timm` installed:
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
python scripts/run_review.py --list
|
|
310
|
+
python scripts/run_review.py all --validate # parse app args, no GPU jobs
|
|
311
|
+
python scripts/run_review.py smoke --dry-run # inspect commands
|
|
312
|
+
python scripts/run_review.py smoke --devices 0,1
|
|
313
|
+
python scripts/run_review.py fsdp_compile naflex_repeat prefix_flex
|
|
314
|
+
python scripts/run_review.py data_ranks # check rank streams are distinct
|
|
315
|
+
python scripts/run_review.py tests parity
|
|
316
|
+
python scripts/run_review.py all
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
The launcher runs scenarios sequentially through `pixr.app.train`, `pixr.app.eval`, pytest and
|
|
320
|
+
`scripts/check_distributed.py`. Scenarios cover DDP / FSDP2, gradient accumulation, compile, checkpointing, EMA,
|
|
321
|
+
NaFlex batching, all three model families, attention backends, checkpoint resume and DocVQA fine-tuning.
|
|
322
|
+
`data_ranks` checks actual resampled WDS sample identities across ranks, without loading a model or decoding PDFs.
|
|
323
|
+
It fails if any two ranks receive an identical stream. App runs also fail if no updates or non-finite losses are logged.
|
|
324
|
+
`parity` compares FP32 DDP / FSDP2 model and EMA parameters and fails above a relative L2 difference of `1e-5`;
|
|
325
|
+
its resumed losses and generated outputs are also recorded for inspection.
|
|
326
|
+
|
|
327
|
+
Defaults are short execution checks: random initialization, 64 global samples per interval, batch 2 per GPU,
|
|
328
|
+
accumulation 2, 256 image patches and 128 text tokens. `--pretrained` enables hub weight initialization for the
|
|
329
|
+
app runs; tokenizers and Qwen3 / Ettin configs can still require downloads without it. `pretrained_tests` downloads
|
|
330
|
+
HF reference weights; `docvqa` uses the HF DocVQA dataset. `--samples`, `--batch-size`, `--accum`, `--patches`,
|
|
331
|
+
`--text-length`, and `--workers` adjust the workload. These short random-weight runs do not measure convergence.
|
|
332
|
+
|
|
333
|
+
The default data paths are sibling `../data/idl/idl-train-000{01..07}.tar` for training and shard `00000` for eval;
|
|
334
|
+
override with `--train-source` / `--eval-source`. `naflex_repeat` needs at least `GPUs * workers` training shards.
|
|
335
|
+
Logs, exact commands, resolved configs, checkpoints and `summary.json` go into a new `../runs/review-<timestamp>`
|
|
336
|
+
directory (`--output` overrides it). Each command has a 20-minute timeout (`--timeout` in seconds). Failed scenarios
|
|
337
|
+
are logged and the remaining scenarios continue; `--fail-fast` stops at the first failure. The launcher exits
|
|
338
|
+
nonzero on failure and prints a `tail -f` command for the active log.
|
|
339
|
+
|
|
340
|
+
## Acknowledgements
|
|
341
|
+
|
|
342
|
+
Model and training design draws on [Donut](https://github.com/clovaai/donut), Pix2Struct, PaLI, LLaVA and GenLIP.
|
|
343
|
+
Image encoders come from [`timm`](https://github.com/huggingface/pytorch-image-models), the training task / FSDP2
|
|
344
|
+
handling and NaFlex batching follow [OpenCLIP](https://github.com/mlfoundations/open_clip), datasets are on the
|
|
345
|
+
Hugging Face Hub under the [`pixparse`](https://huggingface.co/pixparse) organization.
|
|
346
|
+
|
|
347
|
+
## License
|
|
348
|
+
|
|
349
|
+
Apache 2.0, see [LICENSE](LICENSE).
|