ellf-recipes-gpu 0.1.1__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.
@@ -0,0 +1,3 @@
1
+ All Rights Reserved
2
+
3
+ Copyright (C) 2023 ExplosionAI GmbH
@@ -0,0 +1,2 @@
1
+ include LICENSE
2
+ include requirements.in
@@ -0,0 +1,23 @@
1
+ Metadata-Version: 2.4
2
+ Name: ellf-recipes-gpu
3
+ Version: 0.1.1
4
+ Summary: GPU recipes for Ellf (spaCy curated transformers training & inference)
5
+ Home-page: https://prodi.gy
6
+ Author: ExplosionAI GmbH
7
+ Author-email: contact@explosion.ai
8
+ License: All rights reserved
9
+ License-File: LICENSE
10
+ Requires-Dist: ellf-recipes
11
+ Requires-Dist: ellf_recipes_sdk
12
+ Requires-Dist: huggingface-hub>=0.20.0
13
+ Requires-Dist: prodigy-company-plugins
14
+ Requires-Dist: prodigy>=1.16.0
15
+ Requires-Dist: spacy-curated-transformers<1.0.0,>=0.3.0
16
+ Requires-Dist: transformers>=4.30.0
17
+ Dynamic: author
18
+ Dynamic: author-email
19
+ Dynamic: home-page
20
+ Dynamic: license
21
+ Dynamic: license-file
22
+ Dynamic: requires-dist
23
+ Dynamic: summary
@@ -0,0 +1,3 @@
1
+ from .about import __version__
2
+
3
+ __all__ = ["__version__"]
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "ellf-recipes-gpu",
3
+ "version": "0.1.1",
4
+ "summary": "GPU recipes for Ellf (spaCy curated transformers training & inference)",
5
+ "uri": "https://prodi.gy",
6
+ "prog": "ptr",
7
+ "package_data": [],
8
+ "entry_points": {
9
+ "ellf_recipes": [
10
+ "ellf_recipes_gpu = ellf_recipes_gpu.recipes"
11
+ ]
12
+ }
13
+ }
@@ -0,0 +1,23 @@
1
+ """
2
+ This file originates in shared/shared_about.py, and
3
+ is copied verbatim into the different projects. It should
4
+ not be edited directly, edit the shared version and replicate
5
+ it everywhere.
6
+ """
7
+
8
+ import json
9
+ from pathlib import Path
10
+
11
+ PWD = Path(__file__).parent
12
+
13
+
14
+ with (PWD / "about.json").open("r", encoding="utf8") as file_:
15
+ _about_data = json.load(file_)
16
+
17
+
18
+ __name__ = _about_data["name"]
19
+ __title__ = _about_data.get("title", "")
20
+ __description__ = _about_data.get("description", "")
21
+ __summary__ = _about_data.get("summary", "")
22
+ __version__ = _about_data["version"]
23
+ __prog__ = _about_data.get("prog", "")
@@ -0,0 +1,11 @@
1
+ # isort: skip_file
2
+ # The import order determines the order of recipes shown in the UI
3
+ from . import (
4
+ train_curated_transformer,
5
+ apply_curated_transformer,
6
+ )
7
+
8
+ __all__ = [
9
+ "train_curated_transformer",
10
+ "apply_curated_transformer",
11
+ ]
@@ -0,0 +1,118 @@
1
+ from typing import Any, Dict, List, Union
2
+
3
+ import spacy
4
+ from prodigy.errors import RecipeError
5
+ from prodigy.util import msg
6
+
7
+ from ellf_recipes_sdk import (
8
+ Input,
9
+ InputDataset,
10
+ IntProps,
11
+ Model,
12
+ TextProps,
13
+ action_recipe,
14
+ save_examples,
15
+ )
16
+
17
+
18
+ def _doc_predictions(doc) -> Dict[str, Any]: # type: ignore[no-untyped-def]
19
+ """Extract a generic, component-agnostic prediction payload from a Doc.
20
+
21
+ Deliberately simple rather than reproducing every task-specific
22
+ Prodigy annotation format (span boundaries, textcat "accept" shape,
23
+ etc.) for every possible component — this is a batch-inference
24
+ action recipe, not an annotation task recipe, so its output is meant
25
+ to be inspected or consumed downstream rather than re-annotated.
26
+ """
27
+ predictions: Dict[str, Any] = {}
28
+ if doc.ents:
29
+ predictions["ents"] = [
30
+ {"start": ent.start_char, "end": ent.end_char, "label": ent.label_}
31
+ for ent in doc.ents
32
+ ]
33
+ if doc.spans:
34
+ predictions["spans"] = {
35
+ key: [
36
+ {"start": span.start_char, "end": span.end_char, "label": span.label_}
37
+ for span in spans
38
+ ]
39
+ for key, spans in doc.spans.items()
40
+ }
41
+ if doc.cats:
42
+ predictions["cats"] = dict(doc.cats)
43
+ return predictions
44
+
45
+
46
+ @action_recipe(
47
+ title="Apply a spacy-curated-transformers model (GPU)",
48
+ description=(
49
+ "Run inference with a trained spacy-curated-transformers model "
50
+ "over an input dataset or asset, writing predictions to an "
51
+ "output dataset."
52
+ ),
53
+ field_props={
54
+ # fmt: off
55
+ "model": TextProps(
56
+ title="Trained model",
57
+ description="Model asset produced by train-curated-transformer",
58
+ ),
59
+ "gpu_id": IntProps(
60
+ title="GPU device id", description="Use 0 for the first GPU"
61
+ ),
62
+ # fmt: on
63
+ },
64
+ resources={"gpu": 1},
65
+ )
66
+ def apply_curated_transformer(
67
+ *,
68
+ model: Model,
69
+ input: Union[Input, InputDataset],
70
+ output_dataset: str,
71
+ gpu_id: int = 0,
72
+ batch_size: int = 32,
73
+ ) -> None:
74
+ """Run batch inference with a trained spacy-curated-transformers model.
75
+
76
+ Writes ``{"text": ..., "predictions": {...}}`` rows to
77
+ ``output_dataset`` — see ``_doc_predictions`` for the prediction
78
+ shape. Predictions are model output, not user annotation, so they're
79
+ saved as ``server_ann_keys`` rather than ``user_ann_keys``.
80
+
81
+ Contract:
82
+ Preconditions:
83
+ - Every example loaded from ``input`` must have a ``"text"``
84
+ key; a missing one raises ``RecipeError``.
85
+
86
+ Raises:
87
+ RecipeError: if an input example has no ``"text"`` key.
88
+ Various spaCy/torch errors (not caught) if the requested GPU
89
+ device is unavailable or the model fails to load.
90
+ """
91
+ if not spacy.prefer_gpu(gpu_id): # pyright: ignore[reportPrivateImportUsage]
92
+ msg.warn(
93
+ f"Could not activate GPU {gpu_id} — falling back to CPU. "
94
+ "Inference will be slower than expected."
95
+ )
96
+ nlp = model.load()
97
+
98
+ texts: List[str] = []
99
+ for eg in input.load():
100
+ text = eg.get("text")
101
+ if not text:
102
+ raise RecipeError("Every input example must have a non-empty 'text' field.")
103
+ texts.append(text)
104
+
105
+ examples = []
106
+ for text, doc in zip(texts, nlp.pipe(texts, batch_size=batch_size)):
107
+ examples.append({"text": text, "predictions": _doc_predictions(doc)})
108
+
109
+ save_examples(
110
+ output_dataset,
111
+ examples,
112
+ input_keys=["text"],
113
+ server_ann_keys=["predictions"],
114
+ )
115
+ msg.good(f"Wrote {len(examples)} predictions to dataset '{output_dataset}'")
116
+
117
+
118
+ __all__ = ["apply_curated_transformer"]
@@ -0,0 +1,374 @@
1
+ import tempfile
2
+ from enum import Enum
3
+ from pathlib import Path
4
+ from typing import Dict, List, Optional, Tuple
5
+
6
+ import prodigy.recipes.train as prodigy_train
7
+ import spacy
8
+ from prodigy.errors import RecipeError
9
+ from spacy.cli.init_config import init_config as spacy_init_config
10
+ from spacy.cli.init_config import save_config
11
+ from spacy.util import load_config
12
+ from thinc.api import Config
13
+
14
+ from ellf_recipes.recipes.train import (
15
+ COMPONENTS,
16
+ Data,
17
+ OutputSettings,
18
+ _cleanup_temp_datasets,
19
+ _get_pam_context,
20
+ _load_meta_json,
21
+ _parse_config_overrides,
22
+ _preflight_outputs,
23
+ _save_outputs,
24
+ )
25
+ from ellf_recipes_sdk import (
26
+ BoolProps,
27
+ FloatProps,
28
+ IntProps,
29
+ ListProps,
30
+ TextProps,
31
+ action_recipe,
32
+ )
33
+
34
+
35
+ class HfModelType(Enum):
36
+ """Hugging Face model families spacy-curated-transformers can load.
37
+
38
+ Deliberately narrower than the 5 architectures curated-transformers
39
+ registers (it also has ``AlbertTransformer.v1``): its HF-tokenizer
40
+ loader (``tokenization/hf_loader.py``) only converts Bert/Roberta/
41
+ XLMRoberta/Camembert fast tokenizers, so a real Albert checkpoint
42
+ would register cleanly but fail at model-init time. Leaving it out
43
+ here avoids shipping a family that looks supported but isn't.
44
+ """
45
+
46
+ bert = "bert"
47
+ roberta = "roberta"
48
+ camembert = "camembert"
49
+ xlm_roberta = "xlm-roberta"
50
+
51
+
52
+ # (curated-transformer architecture, piece-encoder architecture) per HF
53
+ # model family — from spacy-curated-transformers' own setup.cfg entry
54
+ # points, cross-checked against tokenization/hf_loader.py's tokenizer
55
+ # dispatch so the pairing is actually loadable, not just registered.
56
+ _ARCHITECTURE_BY_MODEL_TYPE: Dict[HfModelType, Tuple[str, str]] = {
57
+ HfModelType.bert: (
58
+ "spacy-curated-transformers.BertTransformer.v1",
59
+ "spacy-curated-transformers.BertWordpieceEncoder.v1",
60
+ ),
61
+ HfModelType.roberta: (
62
+ "spacy-curated-transformers.RobertaTransformer.v1",
63
+ "spacy-curated-transformers.ByteBpeEncoder.v1",
64
+ ),
65
+ HfModelType.camembert: (
66
+ "spacy-curated-transformers.CamembertTransformer.v1",
67
+ "spacy-curated-transformers.CamembertSentencepieceEncoder.v1",
68
+ ),
69
+ HfModelType.xlm_roberta: (
70
+ "spacy-curated-transformers.XlmrTransformer.v1",
71
+ "spacy-curated-transformers.XlmrSentencepieceEncoder.v1",
72
+ ),
73
+ }
74
+
75
+ TRANSFORMER_PIPE_NAME = "transformer"
76
+
77
+
78
+ def _default_curated_transformer_base_config(
79
+ pipes: Dict[str, Tuple[List[str], List[str]]], lang: str
80
+ ) -> Config:
81
+ """Build a tok2vec-listener-based default config for ``pipes``, always
82
+ using spaCy's "accuracy" preset rather than
83
+ ``prodigy.recipes.train.generate_default_config``'s default choice of
84
+ "efficiency" for blank models.
85
+
86
+ Efficiency-mode uses architectures that skip the tok2vec listener
87
+ entirely for some components (e.g. textcat's bag-of-words
88
+ ``TextCatBOW.v3``) — there would be nothing for
89
+ ``_install_curated_transformer`` to redirect at the transformer.
90
+ Accuracy-mode consistently wires every supported component through a
91
+ ``model.tok2vec`` listener (verified against the installed spaCy:
92
+ ner/spancat/tagger/parser/senter/textcat/textcat_multilabel all use
93
+ it under "accuracy"), which is what makes the swap possible. This
94
+ also matches practice: pairing an efficiency-oriented head with an
95
+ already-expensive transformer forward pass isn't a combination
96
+ anyone actually wants.
97
+ """
98
+ config = spacy_init_config(
99
+ lang=lang, pipeline=list(pipes), optimize="accuracy", gpu=False
100
+ )
101
+ if "ner" in config["components"]:
102
+ config["components"]["ner"]["incorrect_spans_key"] = (
103
+ prodigy_train.NER_DEFAULT_INCORRECT_KEY
104
+ )
105
+ if "spancat" in config["components"]:
106
+ config["components"]["spancat"]["spans_key"] = prodigy_train.SPANCAT_DEFAULT_KEY
107
+ prefix = f"spans_{prodigy_train.SPANCAT_DEFAULT_KEY}"
108
+ config["training"]["score_weights"][f"{prefix}_f"] = 1.0
109
+ config["training"]["score_weights"][f"{prefix}_p"] = 0.0
110
+ config["training"]["score_weights"][f"{prefix}_r"] = 0.0
111
+ train_sets, dev_sets = pipes["spancat"]
112
+ db = prodigy_train.connect()
113
+ examples = prodigy_train.load_examples(db, [*train_sets, *dev_sets])
114
+ suggester = prodigy_train.infer_spancat_suggester(examples, spacy.blank(lang))
115
+ config["components"]["spancat"]["suggester"] = suggester
116
+ return config
117
+
118
+
119
+ def _install_curated_transformer(
120
+ config: Config, *, pipes: List[str], hf_model_type: HfModelType
121
+ ) -> None:
122
+ """Replace ``config``'s tok2vec pipe with a curated-transformer
123
+ component in place, redirecting every downstream component's
124
+ listener at it.
125
+
126
+ Raises ``RecipeError`` for any requested component whose default
127
+ "accuracy" architecture doesn't use a ``model.tok2vec`` listener —
128
+ there would be nothing correct to redirect.
129
+ """
130
+ transformer_arch, piece_encoder_arch = _ARCHITECTURE_BY_MODEL_TYPE[hf_model_type]
131
+ pipeline = list(config["nlp"]["pipeline"])
132
+ if "tok2vec" in pipeline:
133
+ pipeline.remove("tok2vec")
134
+ config["components"].pop("tok2vec", None)
135
+ if TRANSFORMER_PIPE_NAME not in pipeline:
136
+ pipeline.insert(0, TRANSFORMER_PIPE_NAME)
137
+ config["nlp"]["pipeline"] = pipeline
138
+ config["components"][TRANSFORMER_PIPE_NAME] = {
139
+ "factory": "curated_transformer",
140
+ "model": {
141
+ "@architectures": transformer_arch,
142
+ # Placeholder — overwritten by init_fill_config_curated_transformer
143
+ # (via _fill_curated_transformer_from_hf below) with the real HF
144
+ # model config's vocab_size, hidden_width, num_hidden_layers, etc.
145
+ "vocab_size": 1,
146
+ "piece_encoder": {"@architectures": piece_encoder_arch},
147
+ "with_spans": {
148
+ "@architectures": "spacy-curated-transformers.WithStridedSpans.v1",
149
+ "stride": 96,
150
+ "window": 128,
151
+ },
152
+ },
153
+ }
154
+ for component in pipes:
155
+ model = config["components"][component]["model"]
156
+ if "tok2vec" not in model:
157
+ raise RecipeError(
158
+ f"Component {component!r} has no tok2vec listener to redirect "
159
+ f"to the curated transformer (its default architecture is "
160
+ f"{model.get('@architectures')!r}). GPU training via "
161
+ f"spacy-curated-transformers currently supports components "
162
+ f"whose default config wires a tok2vec listener."
163
+ )
164
+ model["tok2vec"] = {
165
+ "@architectures": "spacy-curated-transformers.LastTransformerLayerListener.v1",
166
+ # Placeholder — corrected below to match the transformer's real
167
+ # hidden width, once known.
168
+ "width": 768,
169
+ "pooling": {"@layers": "reduce_mean.v1"},
170
+ "upstream": "*",
171
+ }
172
+
173
+
174
+ def _fill_curated_transformer_from_hf(
175
+ config: Config, *, hf_model_name: str, hf_model_revision: str
176
+ ) -> Config:
177
+ """Fill the transformer component's model hyperparameters (vocab
178
+ size, hidden width, layer count, ...) from the real Hugging Face
179
+ model config, and set its encoder/piece-encoder loaders to pull
180
+ weights from ``hf_model_name`` at load time.
181
+
182
+ Delegates to spacy-curated-transformers' own ``init fill-curated-
183
+ transformer`` implementation rather than re-deriving the HF-config
184
+ field mapping here — that mapping is version-specific to the
185
+ installed spacy-curated-transformers and re-implementing it would
186
+ drift out of sync silently. It also validates the HF model's actual
187
+ type against the architecture chosen in ``_install_curated_transformer``
188
+ and fails with a clear message on mismatch (e.g. picking "roberta"
189
+ but naming a BERT checkpoint).
190
+
191
+ Only fills the transformer's own ``model`` block — listener
192
+ ``width`` on every downstream component must still be propagated
193
+ from the resolved ``hidden_width`` by the caller, since this step
194
+ doesn't know about them.
195
+ """
196
+ from spacy_curated_transformers.cli.fill_config_transformer import (
197
+ init_fill_config_curated_transformer,
198
+ )
199
+
200
+ with tempfile.NamedTemporaryFile(suffix=".cfg", mode="w", delete=False) as tmp:
201
+ tmp_path = Path(tmp.name)
202
+ try:
203
+ save_config(config, tmp_path, is_stdout=False, silent=True)
204
+ init_fill_config_curated_transformer(
205
+ tmp_path,
206
+ tmp_path,
207
+ cli_model_name=hf_model_name,
208
+ cli_model_revision=hf_model_revision,
209
+ cli_transformer_name=TRANSFORMER_PIPE_NAME,
210
+ config_overrides={},
211
+ )
212
+ filled = load_config(tmp_path)
213
+ finally:
214
+ tmp_path.unlink(missing_ok=True)
215
+
216
+ hidden_width = filled["components"][TRANSFORMER_PIPE_NAME]["model"]["hidden_width"]
217
+ for component in filled["components"].values():
218
+ model = component.get("model", {})
219
+ tok2vec = model.get("tok2vec")
220
+ if (
221
+ isinstance(tok2vec, dict)
222
+ and tok2vec.get("@architectures")
223
+ == "spacy-curated-transformers.LastTransformerLayerListener.v1"
224
+ ):
225
+ tok2vec["width"] = hidden_width
226
+ return filled
227
+
228
+
229
+ @action_recipe(
230
+ title="Train a spaCy pipeline with a curated transformer (GPU)",
231
+ description=(
232
+ "Train a spaCy pipeline using spacy-curated-transformers for GPU-"
233
+ "accelerated training and inference, loading weights from a "
234
+ "Hugging Face checkpoint."
235
+ ),
236
+ field_props={
237
+ # fmt: off
238
+ "hf_model_name": TextProps(
239
+ title="Hugging Face model name",
240
+ description="e.g. 'roberta-base', 'bert-base-cased', 'xlm-roberta-base'",
241
+ ),
242
+ "hf_model_revision": TextProps(
243
+ title="Hugging Face model revision",
244
+ description="Branch or commit to load. Defaults to 'main'.",
245
+ ),
246
+ "lang": TextProps(title="Language code", description="e.g. 'en'"),
247
+ "gpu_id": IntProps(
248
+ title="GPU device id", description="Use 0 for the first GPU"
249
+ ),
250
+ "eval_split": FloatProps(
251
+ title="Portion of examples to split off for evaluation",
252
+ description="Applied if no dedicated evaluation datasets are provided for a component.",
253
+ min=0.0,
254
+ max=1.0,
255
+ step=0.05,
256
+ ),
257
+ "label_stats": BoolProps(title="Show per-label scores"),
258
+ "verbose": BoolProps(title="Enable verbose logging"),
259
+ "config_overrides": ListProps(
260
+ title="Config overrides",
261
+ description="Override config values for training",
262
+ exists=False,
263
+ min=0,
264
+ ),
265
+ # fmt: on
266
+ },
267
+ cli_names={
268
+ **{f"data.{c}.training-input-dataset": f"{c}.train" for c in COMPONENTS},
269
+ **{f"data.{c}.training-input": f"{c}.train-asset" for c in COMPONENTS},
270
+ **{f"data.{c}.evaluation-input-dataset": f"{c}.eval" for c in COMPONENTS},
271
+ **{f"data.{c}.evaluation-input": f"{c}.eval-asset" for c in COMPONENTS},
272
+ },
273
+ resources={"gpu": 1},
274
+ )
275
+ def train_curated_transformer(
276
+ *,
277
+ data: Data,
278
+ output: OutputSettings,
279
+ hf_model_type: HfModelType,
280
+ hf_model_name: str,
281
+ hf_model_revision: str = "main",
282
+ lang: str = "en",
283
+ gpu_id: int = 0,
284
+ eval_split: float = 0.2,
285
+ label_stats: bool = False,
286
+ verbose: bool = False,
287
+ config_overrides: Optional[List[str]] = None,
288
+ ) -> None:
289
+ """Train a spaCy pipeline with a spacy-curated-transformers component
290
+ on GPU, loading weights from a Hugging Face checkpoint.
291
+
292
+ Mirrors the base ``ellf_recipes`` ``train`` recipe's data handling,
293
+ validation, and output persistence, but builds a curated-transformer
294
+ config instead of a tok2vec one and trains with a real ``gpu_id``
295
+ instead of the CPU recipe's hardcoded ``-1``.
296
+
297
+ Contract:
298
+ Preconditions:
299
+ - Same as ``ellf_recipes.recipes.train.train``: ``data`` must
300
+ contain at least one non-None component; ``output.name``
301
+ required unless ``output.skip``; each ``config_overrides``
302
+ entry must contain ``"="``.
303
+ - ``hf_model_type`` must match the actual type of the model at
304
+ ``hf_model_name`` (validated against the real HF config
305
+ during the fill-in step; raises a clear error on mismatch).
306
+ - Every requested component's default "accuracy" architecture
307
+ must use a ``model.tok2vec`` listener (raises ``RecipeError``
308
+ otherwise — see ``_install_curated_transformer``).
309
+
310
+ Raises:
311
+ RecipeError: on the precondition failures above, or from
312
+ spacy-curated-transformers' own HF-loading errors
313
+ (unreachable model name/revision, unsupported HF
314
+ tokenizer type).
315
+ """
316
+ output.validate()
317
+ config_overrides_dict = _parse_config_overrides(config_overrides or [])
318
+ prodigy_train.set_log_level(verbose=verbose)
319
+ pam_client = None
320
+ cluster_id = None
321
+ if not output.skip:
322
+ pam_client, cluster_id = _get_pam_context()
323
+ _preflight_outputs(output, pam_client, cluster_id)
324
+ pipes, temp_datasets = data.materialize()
325
+ try:
326
+ if not pipes:
327
+ raise RecipeError("No components to train")
328
+ base_config = _default_curated_transformer_base_config(pipes, lang)
329
+ _install_curated_transformer(
330
+ base_config, pipes=list(pipes), hf_model_type=hf_model_type
331
+ )
332
+ transformer_config = _fill_curated_transformer_from_hf(
333
+ base_config,
334
+ hf_model_name=hf_model_name,
335
+ hf_model_revision=hf_model_revision,
336
+ )
337
+ with tempfile.TemporaryDirectory() as tmp_dir:
338
+ tmp_dir = Path(tmp_dir)
339
+ train_config = prodigy_train._prodigy_config(
340
+ pipes,
341
+ None,
342
+ lang=lang,
343
+ eval_split=eval_split,
344
+ config=transformer_config,
345
+ verbose=verbose,
346
+ )
347
+ prodigy_train._train(
348
+ train_config,
349
+ output_dir=tmp_dir,
350
+ overrides=config_overrides_dict,
351
+ gpu_id=gpu_id,
352
+ show_label_stats=label_stats,
353
+ )
354
+ if output.skip:
355
+ prodigy_train.msg.warn(
356
+ "Skipping output registration. Model and results were NOT "
357
+ "saved. Re-run with 'Skip saving outputs' unticked to "
358
+ "persist them."
359
+ )
360
+ else:
361
+ assert pam_client is not None and cluster_id is not None
362
+ model_best = tmp_dir / "model-best"
363
+ _save_outputs(
364
+ output,
365
+ pam_client,
366
+ cluster_id,
367
+ model_dir=model_best,
368
+ results=_load_meta_json(model_best),
369
+ )
370
+ finally:
371
+ _cleanup_temp_datasets(temp_datasets)
372
+
373
+
374
+ __all__ = ["train_curated_transformer", "HfModelType"]
@@ -0,0 +1,23 @@
1
+ Metadata-Version: 2.4
2
+ Name: ellf-recipes-gpu
3
+ Version: 0.1.1
4
+ Summary: GPU recipes for Ellf (spaCy curated transformers training & inference)
5
+ Home-page: https://prodi.gy
6
+ Author: ExplosionAI GmbH
7
+ Author-email: contact@explosion.ai
8
+ License: All rights reserved
9
+ License-File: LICENSE
10
+ Requires-Dist: ellf-recipes
11
+ Requires-Dist: ellf_recipes_sdk
12
+ Requires-Dist: huggingface-hub>=0.20.0
13
+ Requires-Dist: prodigy-company-plugins
14
+ Requires-Dist: prodigy>=1.16.0
15
+ Requires-Dist: spacy-curated-transformers<1.0.0,>=0.3.0
16
+ Requires-Dist: transformers>=4.30.0
17
+ Dynamic: author
18
+ Dynamic: author-email
19
+ Dynamic: home-page
20
+ Dynamic: license
21
+ Dynamic: license-file
22
+ Dynamic: requires-dist
23
+ Dynamic: summary
@@ -0,0 +1,19 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ pyproject.toml
4
+ requirements.in
5
+ setup.cfg
6
+ setup.py
7
+ ellf_recipes_gpu/__init__.py
8
+ ellf_recipes_gpu/about.json
9
+ ellf_recipes_gpu/about.py
10
+ ellf_recipes_gpu.egg-info/PKG-INFO
11
+ ellf_recipes_gpu.egg-info/SOURCES.txt
12
+ ellf_recipes_gpu.egg-info/dependency_links.txt
13
+ ellf_recipes_gpu.egg-info/entry_points.txt
14
+ ellf_recipes_gpu.egg-info/not-zip-safe
15
+ ellf_recipes_gpu.egg-info/requires.txt
16
+ ellf_recipes_gpu.egg-info/top_level.txt
17
+ ellf_recipes_gpu/recipes/__init__.py
18
+ ellf_recipes_gpu/recipes/apply_curated_transformer.py
19
+ ellf_recipes_gpu/recipes/train_curated_transformer.py
@@ -0,0 +1,2 @@
1
+ [ellf_recipes]
2
+ ellf_recipes_gpu = ellf_recipes_gpu.recipes
@@ -0,0 +1,7 @@
1
+ ellf-recipes
2
+ ellf_recipes_sdk
3
+ huggingface-hub>=0.20.0
4
+ prodigy-company-plugins
5
+ prodigy>=1.16.0
6
+ spacy-curated-transformers<1.0.0,>=0.3.0
7
+ transformers>=4.30.0
@@ -0,0 +1 @@
1
+ ellf_recipes_gpu
@@ -0,0 +1,9 @@
1
+ [build-system]
2
+ build-backend = "setuptools.build_meta"
3
+ requires = ["setuptools", "wheel"]
4
+
5
+ [tool.pytest.ini_options]
6
+ testpaths = ["tests"]
7
+
8
+ [tool.pyright]
9
+ extraPaths = [".", "../sdk_recipes"]
@@ -0,0 +1,9 @@
1
+ # This is a generated file! Do not edit directly.
2
+ # Instead run: pdcli repo write-requirements
3
+ ellf-recipes
4
+ ellf_recipes_sdk
5
+ huggingface-hub>=0.20.0
6
+ prodigy-company-plugins
7
+ prodigy>=1.16.0
8
+ spacy-curated-transformers<1.0.0,>=0.3.0
9
+ transformers>=4.30.0
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ This file originates in shared/shared_setup.py, and
4
+ is copied verbatim into the different projects. It should
5
+ not be edited directly, edit the shared version and replicate
6
+ it everywhere.
7
+ """
8
+
9
+ import json
10
+ from pathlib import Path
11
+ from typing import Any, Dict, List
12
+
13
+ from setuptools import find_packages, setup
14
+
15
+ PWD = Path(__file__).parent
16
+ EXCLUDED_PACKAGE_DATA_PARTS = {".git", "__pycache__", "tests", "backups", "evals"}
17
+ EXCLUDED_PACKAGE_DATA_FILENAMES = {"CLAUDE.md", "README.md"}
18
+
19
+
20
+ def read_about(path: Path) -> Dict[str, Any]:
21
+ with (path / "about.json").open("r", encoding="utf8") as file_:
22
+ data = json.loads(file_.read())
23
+ return data
24
+
25
+
26
+ def read_requirements(path: Path) -> List[str]:
27
+ # Read in requirements and split into packages and URLs
28
+ requirements_path = path / "requirements.in"
29
+ with requirements_path.open("r", encoding="utf8") as f:
30
+ requirements = [line.strip() for line in f]
31
+ return requirements
32
+
33
+
34
+ def should_include_package_data(path: Path, package_path: Path) -> bool:
35
+ rel_path = path.relative_to(package_path)
36
+ if not path.is_file():
37
+ return False
38
+ if any(part in EXCLUDED_PACKAGE_DATA_PARTS for part in rel_path.parts):
39
+ return False
40
+ if path.name in EXCLUDED_PACKAGE_DATA_FILENAMES:
41
+ return False
42
+ if path.suffix == ".pyc":
43
+ return False
44
+ return True
45
+
46
+
47
+ def setup_package():
48
+ root = PWD.resolve()
49
+ packages = [
50
+ p for p in find_packages() if not p.startswith("tests") and p != "migrations"
51
+ ]
52
+ package_name = packages[0]
53
+ package_path = root / package_name
54
+ about = read_about(root / package_name)
55
+ requirements = read_requirements(root)
56
+ version = about["version"]
57
+ package_data = about.get("package_data", [])
58
+ package_data_dirs = about.get("package_data_dirs", [])
59
+ for directory in package_data_dirs:
60
+ # Package data doesn't properly support recursive globs, so we fix them.
61
+ package_data.extend(
62
+ [
63
+ str(path.relative_to(package_path))
64
+ for path in (package_path / directory).glob("**/*")
65
+ if should_include_package_data(path, package_path)
66
+ ]
67
+ )
68
+ # Ensure the about.json is packaged
69
+ if "about.json" not in package_data:
70
+ package_data.append("about.json")
71
+ setup(
72
+ author=about.get("author", "ExplosionAI GmbH"),
73
+ author_email=about.get("email", "contact@explosion.ai"),
74
+ url=about.get("uri", "https://github.com/explosion/ellf"),
75
+ license=about.get("license", "All rights reserved"),
76
+ name=about["name"],
77
+ description=about["summary"],
78
+ version=version,
79
+ packages=packages,
80
+ package_data={package_name: package_data},
81
+ entry_points=about.get("entry_points", {}),
82
+ install_requires=requirements,
83
+ scripts=[],
84
+ zip_safe=False,
85
+ )
86
+
87
+
88
+ if __name__ == "__main__":
89
+ setup_package()