cureta 0.1.0__py3-none-any.whl
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.
- cureta/__init__.py +136 -0
- cureta/base_tagger.py +270 -0
- cureta/cli.py +816 -0
- cureta/config.py +632 -0
- cureta/data_sources.py +417 -0
- cureta/document.py +135 -0
- cureta/external_taggers/__init__.py +22 -0
- cureta/external_taggers/base.py +88 -0
- cureta/external_taggers/datatrove.py +333 -0
- cureta/external_taggers/datatrove_fused.py +143 -0
- cureta/external_taggers/nemo.py +218 -0
- cureta/heuristic_taggers/c4_quality_tagger.py +85 -0
- cureta/heuristic_taggers/compression_ratio_tagger.py +37 -0
- cureta/heuristic_taggers/content_type_tagger.py +74 -0
- cureta/heuristic_taggers/date_mention_tagger.py +64 -0
- cureta/heuristic_taggers/exact_norm_hash_tagger.py +48 -0
- cureta/heuristic_taggers/fineweb_quality_tagger.py +73 -0
- cureta/heuristic_taggers/gopher_quality_tagger.py +95 -0
- cureta/heuristic_taggers/heuristic_taggers.py +285 -0
- cureta/heuristic_taggers/html_density_tagger.py +47 -0
- cureta/heuristic_taggers/markdown_structure_tagger.py +57 -0
- cureta/heuristic_taggers/minhash_tagger.py +58 -0
- cureta/heuristic_taggers/paragraph_stats_tagger.py +39 -0
- cureta/heuristic_taggers/pii_regex_tagger.py +57 -0
- cureta/heuristic_taggers/readability_tagger.py +57 -0
- cureta/heuristic_taggers/setu/constants.py +282 -0
- cureta/heuristic_taggers/setu/setu_filters.py +631 -0
- cureta/heuristic_taggers/simhash_tagger.py +54 -0
- cureta/heuristic_taggers/type_token_ratio_tagger.py +58 -0
- cureta/heuristic_taggers/url_blocklist_tagger.py +93 -0
- cureta/heuristic_taggers/url_parse_tagger.py +53 -0
- cureta/heuristic_taggers/utils.py +15 -0
- cureta/heuristic_taggers/word_length_stats_tagger.py +38 -0
- cureta/infra/__init__.py +15 -0
- cureta/infra/distributed_runner.py +183 -0
- cureta/infra/engine.py +329 -0
- cureta/infra/skypilot_cluster.py +291 -0
- cureta/manifest.py +196 -0
- cureta/pipeline.py +353 -0
- cureta/registry.py +584 -0
- cureta/results.py +83 -0
- cureta/runner.py +763 -0
- cureta/tag_ops.py +96 -0
- cureta/taggers/__init__.py +31 -0
- cureta/taggers/detoxify_tagger.py +67 -0
- cureta/taggers/domain_classifier_tagger.py +91 -0
- cureta/taggers/fasttext_quality_tagger.py +77 -0
- cureta/taggers/fineweb_edu_tagger.py +103 -0
- cureta/taggers/glotlid_tagger.py +85 -0
- cureta/taggers/indic_lid_tagger.py +200 -0
- cureta/taggers/llm_judge_tagger.py +128 -0
- cureta/taggers/mmbert_quality_tagger.py +263 -0
- cureta/taggers/paragraph_langid_tagger.py +68 -0
- cureta/taggers/perplexity_tagger.py +586 -0
- cureta/taggers/presidio_pii_tagger.py +73 -0
- cureta/taggers/programming_language_tagger.py +90 -0
- cureta/taggers/sentence_embedding_tagger.py +76 -0
- cureta-0.1.0.dist-info/METADATA +176 -0
- cureta-0.1.0.dist-info/RECORD +61 -0
- cureta-0.1.0.dist-info/WHEEL +4 -0
- cureta-0.1.0.dist-info/entry_points.txt +2 -0
cureta/__init__.py
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""Cureta: Unified Data Curation Framework.
|
|
2
|
+
|
|
3
|
+
.. attribute:: __version__
|
|
4
|
+
|
|
5
|
+
Package version string resolved from installed package metadata
|
|
6
|
+
(e.g. ``"0.1.0"``). Falls back to ``"0.0.0+unknown"`` when the
|
|
7
|
+
package is not installed (e.g. in an editable development checkout
|
|
8
|
+
without ``pip install -e .`` having been run).
|
|
9
|
+
|
|
10
|
+
A pipeline-based library that standardises data processing into a sequence
|
|
11
|
+
of **Taggers** which enrich a standard **Document** object with extracted
|
|
12
|
+
features and metadata.
|
|
13
|
+
|
|
14
|
+
Execution surfaces
|
|
15
|
+
------------------
|
|
16
|
+
run_pipeline -- Canonical entry point; runs end-to-end, returns PipelineResult.
|
|
17
|
+
iter_pipeline_chunks -- Generator variant; yields ChunkResult after each chunk.
|
|
18
|
+
quick_tag -- REPL one-shot; runs taggers on a single string, returns dict.
|
|
19
|
+
stream_tagged_batches -- Streaming without disk writes; yields pd.DataFrame batches.
|
|
20
|
+
|
|
21
|
+
Result types
|
|
22
|
+
------------
|
|
23
|
+
PipelineResult -- Structured summary of a completed run.
|
|
24
|
+
ChunkResult -- Per-chunk timing and output path.
|
|
25
|
+
|
|
26
|
+
Config / composition types
|
|
27
|
+
--------------------------
|
|
28
|
+
PipelineConfig -- Pydantic model for pipeline-level configuration.
|
|
29
|
+
PipelineStageConfig -- Pydantic model for a single pipeline stage.
|
|
30
|
+
TaggerConfig -- Pydantic model for per-tagger configuration.
|
|
31
|
+
ClusterConfig -- Pydantic model for SkyPilot cluster configuration.
|
|
32
|
+
ExecutionMode -- Enum for SIMD / SDMI / AUTO execution strategies.
|
|
33
|
+
ExecutionConfig -- Pydantic model for per-resource-type execution mode.
|
|
34
|
+
OutputFormat -- Enum for output file format (parquet / jsonl).
|
|
35
|
+
|
|
36
|
+
Authoring types
|
|
37
|
+
---------------
|
|
38
|
+
Document -- The canonical data envelope.
|
|
39
|
+
BaseTagger -- Abstract base for all taggers.
|
|
40
|
+
CPUTagger -- Base class for CPU-bound taggers.
|
|
41
|
+
GPUTagger -- Base class for GPU-bound taggers.
|
|
42
|
+
|
|
43
|
+
Composition
|
|
44
|
+
-----------
|
|
45
|
+
Pipeline -- Orchestrator; use Pipeline.from_config() or Pipeline.from_taggers()
|
|
46
|
+
to build pipelines programmatically without YAML.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
from importlib.metadata import PackageNotFoundError
|
|
50
|
+
from importlib.metadata import version as _pkg_version
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
__version__: str = _pkg_version("cureta")
|
|
54
|
+
except PackageNotFoundError:
|
|
55
|
+
__version__ = "0.0.0+unknown"
|
|
56
|
+
|
|
57
|
+
from cureta import tag_ops # noqa: F401 - re-exported for convenience
|
|
58
|
+
from cureta.base_tagger import BaseTagger, CPUTagger, GPUTagger
|
|
59
|
+
from cureta.config import (
|
|
60
|
+
ClusterConfig,
|
|
61
|
+
ExecutionConfig,
|
|
62
|
+
ExecutionMode,
|
|
63
|
+
OutputFormat,
|
|
64
|
+
PipelineConfig,
|
|
65
|
+
PipelineStageConfig,
|
|
66
|
+
TaggerConfig,
|
|
67
|
+
)
|
|
68
|
+
from cureta.document import Document
|
|
69
|
+
from cureta.manifest import read_manifest, write_manifest
|
|
70
|
+
from cureta.pipeline import Pipeline
|
|
71
|
+
from cureta.results import ChunkResult, PipelineResult
|
|
72
|
+
from cureta.runner import (
|
|
73
|
+
iter_pipeline_chunks,
|
|
74
|
+
quick_tag,
|
|
75
|
+
run_pipeline,
|
|
76
|
+
stream_tagged_batches,
|
|
77
|
+
)
|
|
78
|
+
__all__ = [
|
|
79
|
+
# Package version
|
|
80
|
+
"__version__",
|
|
81
|
+
# Execution surfaces (canonical)
|
|
82
|
+
"run_pipeline",
|
|
83
|
+
"iter_pipeline_chunks",
|
|
84
|
+
"quick_tag",
|
|
85
|
+
"stream_tagged_batches",
|
|
86
|
+
# Result types
|
|
87
|
+
"PipelineResult",
|
|
88
|
+
"ChunkResult",
|
|
89
|
+
# Config types
|
|
90
|
+
"PipelineConfig",
|
|
91
|
+
"PipelineStageConfig",
|
|
92
|
+
"TaggerConfig",
|
|
93
|
+
"ClusterConfig",
|
|
94
|
+
"ExecutionMode",
|
|
95
|
+
"ExecutionConfig",
|
|
96
|
+
"OutputFormat",
|
|
97
|
+
# Composition
|
|
98
|
+
"Pipeline",
|
|
99
|
+
# Authoring
|
|
100
|
+
"Document",
|
|
101
|
+
"BaseTagger",
|
|
102
|
+
"CPUTagger",
|
|
103
|
+
"GPUTagger",
|
|
104
|
+
# Helper modules
|
|
105
|
+
"tag_ops",
|
|
106
|
+
# Manifest / Provenance
|
|
107
|
+
"write_manifest",
|
|
108
|
+
"read_manifest",
|
|
109
|
+
# Optional / lazy-loaded
|
|
110
|
+
"IndicLIDTagger",
|
|
111
|
+
"DistributedRunner",
|
|
112
|
+
"SkyPilotCluster",
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def __getattr__(name: str): # noqa: ANN202
|
|
117
|
+
"""Lazy import for optional-dependency modules.
|
|
118
|
+
|
|
119
|
+
DistributedRunner requires ``ray[data]``. IndicLIDTagger and the other
|
|
120
|
+
GPU taggers require ``torch``/``transformers``. Deferring these imports
|
|
121
|
+
avoids breaking users who have not installed the optional extras.
|
|
122
|
+
"""
|
|
123
|
+
if name == "IndicLIDTagger":
|
|
124
|
+
from cureta.taggers.indic_lid_tagger import IndicLIDTagger
|
|
125
|
+
|
|
126
|
+
return IndicLIDTagger
|
|
127
|
+
if name == "DistributedRunner":
|
|
128
|
+
from cureta.infra.distributed_runner import DistributedRunner
|
|
129
|
+
|
|
130
|
+
return DistributedRunner
|
|
131
|
+
if name == "SkyPilotCluster":
|
|
132
|
+
from cureta.infra.skypilot_cluster import SkyPilotCluster
|
|
133
|
+
|
|
134
|
+
return SkyPilotCluster
|
|
135
|
+
msg = f"module {__name__!r} has no attribute {name!r}"
|
|
136
|
+
raise AttributeError(msg)
|
cureta/base_tagger.py
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"""Tagger architecture for the Cureta framework.
|
|
2
|
+
|
|
3
|
+
Provides the abstract base class :class:`BaseTagger` and two intermediate
|
|
4
|
+
abstract subclasses -- :class:`CPUTagger` and :class:`GPUTagger` -- that every
|
|
5
|
+
concrete tagger must inherit from.
|
|
6
|
+
|
|
7
|
+
Each tagger exposes:
|
|
8
|
+
|
|
9
|
+
* :meth:`process_document` -- Tier-1 single-document logic (simple API).
|
|
10
|
+
* :meth:`run` -- Tier-2 batch interface for vectorised processing.
|
|
11
|
+
|
|
12
|
+
Implement exactly **one** of the two. The framework calls ``run()``; the
|
|
13
|
+
default ``run()`` delegates to ``process_document()`` row by row.
|
|
14
|
+
|
|
15
|
+
* :attr:`resources` -- ``dict`` with ``num_cpus`` / ``num_gpus``.
|
|
16
|
+
* :attr:`use_actors` -- whether Ray should use ``ActorPoolStrategy``.
|
|
17
|
+
|
|
18
|
+
Hierarchy
|
|
19
|
+
---------
|
|
20
|
+
::
|
|
21
|
+
|
|
22
|
+
BaseTagger (ABC)
|
|
23
|
+
|- CPUTagger (ABC) -- taggers that run on CPU only
|
|
24
|
+
|- GPUTagger (ABC) -- taggers that require GPU resources
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
import logging
|
|
30
|
+
import re
|
|
31
|
+
import uuid
|
|
32
|
+
from abc import ABC
|
|
33
|
+
from typing import Any
|
|
34
|
+
|
|
35
|
+
import pandas as pd
|
|
36
|
+
|
|
37
|
+
from cureta.config import ExecutionMode, TaggerConfig
|
|
38
|
+
from cureta.document import Document
|
|
39
|
+
|
|
40
|
+
logger = logging.getLogger(__name__)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class BaseTagger(ABC):
|
|
44
|
+
"""Abstract base class for all feature-extraction taggers.
|
|
45
|
+
|
|
46
|
+
Parameters
|
|
47
|
+
----------
|
|
48
|
+
config : TaggerConfig
|
|
49
|
+
Validated configuration for this tagger instance.
|
|
50
|
+
|
|
51
|
+
Raises
|
|
52
|
+
------
|
|
53
|
+
ValueError
|
|
54
|
+
If :meth:`validate_config` determines the configuration is invalid.
|
|
55
|
+
|
|
56
|
+
Notes
|
|
57
|
+
-----
|
|
58
|
+
**Column preservation guarantee:** Any column present in the input
|
|
59
|
+
batch will be present, unchanged, in the output batch. Taggers may
|
|
60
|
+
modify ``document_id``, ``raw_content``, ``metadata``, and ``tags``.
|
|
61
|
+
They must not modify or drop any other column. Tier-2 taggers that
|
|
62
|
+
override :meth:`run` are responsible for upholding this contract.
|
|
63
|
+
|
|
64
|
+
**Two-tier API:** Override :meth:`process_document` for simple per-document
|
|
65
|
+
logic (Tier-1, ~90% of taggers). Override :meth:`run` for vectorised or
|
|
66
|
+
GPU batch operations (Tier-2). The framework dispatches to whichever is
|
|
67
|
+
overridden; if neither is overridden, pipeline construction raises
|
|
68
|
+
:class:`TypeError`.
|
|
69
|
+
|
|
70
|
+
**Preferred execution mode:** subclasses may set the class attribute
|
|
71
|
+
``preferred_mode`` to hint to the runner which execution strategy works
|
|
72
|
+
best for them. A mismatch between the tagger's preference and the
|
|
73
|
+
pipeline's configured mode triggers a startup warning. ``None`` means
|
|
74
|
+
no preference — either mode is acceptable.
|
|
75
|
+
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
preferred_mode: ExecutionMode | None = None
|
|
79
|
+
|
|
80
|
+
def __init__(
|
|
81
|
+
self,
|
|
82
|
+
config: TaggerConfig | None = None,
|
|
83
|
+
**parameters: Any,
|
|
84
|
+
) -> None:
|
|
85
|
+
"""Initialise the tagger with its config or keyword parameters.
|
|
86
|
+
|
|
87
|
+
When *config* is ``None`` the tagger constructs a :class:`TaggerConfig`
|
|
88
|
+
automatically from the class name and any *parameters* kwargs, enabling
|
|
89
|
+
direct instantiation without YAML::
|
|
90
|
+
|
|
91
|
+
tagger = NumWordsTagger(lang="hi")
|
|
92
|
+
"""
|
|
93
|
+
if config is None:
|
|
94
|
+
config = TaggerConfig(
|
|
95
|
+
tagger_name=self._default_name(),
|
|
96
|
+
tagger_class=f"{type(self).__module__}.{type(self).__name__}",
|
|
97
|
+
parameters=parameters,
|
|
98
|
+
)
|
|
99
|
+
self.config = config
|
|
100
|
+
self.validate_config()
|
|
101
|
+
logger.info("Initialised tagger '%s'", config.tagger_name)
|
|
102
|
+
|
|
103
|
+
@classmethod
|
|
104
|
+
def _default_name(cls) -> str:
|
|
105
|
+
"""Derive a snake_case registry name from the class name.
|
|
106
|
+
|
|
107
|
+
``NumWordsTagger`` → ``num_words``, ``CuretaIDTagger`` → ``cureta_id``.
|
|
108
|
+
"""
|
|
109
|
+
name = cls.__name__.removesuffix("Tagger")
|
|
110
|
+
# Insert _ between a lowercase letter and the next uppercase letter.
|
|
111
|
+
s1 = re.sub(r"([a-z])([A-Z])", r"\1_\2", name)
|
|
112
|
+
# Insert _ between a run of uppercase letters and a trailing uppercase+lowercase.
|
|
113
|
+
s2 = re.sub(r"([A-Z]+)([A-Z][a-z])", r"\1_\2", s1)
|
|
114
|
+
return s2.lower()
|
|
115
|
+
|
|
116
|
+
# ------------------------------------------------------------------
|
|
117
|
+
# Abstract interface
|
|
118
|
+
# ------------------------------------------------------------------
|
|
119
|
+
|
|
120
|
+
def process_document(self, document: Document) -> Document:
|
|
121
|
+
"""Tier-1 API: process a single document.
|
|
122
|
+
|
|
123
|
+
Override this for simple, per-document logic. The framework handles
|
|
124
|
+
batching, column preservation, and tag merging.
|
|
125
|
+
|
|
126
|
+
If you override ``run()`` instead (Tier-2), this method is unused and
|
|
127
|
+
you do not need to implement it.
|
|
128
|
+
|
|
129
|
+
Raises
|
|
130
|
+
------
|
|
131
|
+
NotImplementedError
|
|
132
|
+
If neither this method nor ``run()`` is overridden.
|
|
133
|
+
|
|
134
|
+
"""
|
|
135
|
+
raise NotImplementedError(
|
|
136
|
+
f"Tagger '{self.name}' must override either `process_document` "
|
|
137
|
+
f"(Tier-1) or `run` (Tier-2). See docs/writing_taggers.md."
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# ------------------------------------------------------------------
|
|
141
|
+
# Batch interface (used by Ray map_batches)
|
|
142
|
+
# ------------------------------------------------------------------
|
|
143
|
+
|
|
144
|
+
def run(self, batch: pd.DataFrame) -> pd.DataFrame:
|
|
145
|
+
"""Process a batch of documents as a pandas DataFrame.
|
|
146
|
+
|
|
147
|
+
The default implementation iterates rows, deserialises each into
|
|
148
|
+
a :class:`Document`, calls :meth:`process_document`, and writes
|
|
149
|
+
the enriched fields back. Subclasses may override this for
|
|
150
|
+
vectorised / batch-optimised processing.
|
|
151
|
+
|
|
152
|
+
``load_model()`` is called lazily on the first invocation so
|
|
153
|
+
that heavy resources are initialised inside Ray workers rather
|
|
154
|
+
than on the driver (which would cause serialisation failures).
|
|
155
|
+
|
|
156
|
+
Extra columns present in the input batch are preserved unchanged
|
|
157
|
+
in the output. Only ``document_id``, ``raw_content``,
|
|
158
|
+
``metadata``, and ``tags`` may be modified by the tagger.
|
|
159
|
+
"""
|
|
160
|
+
self.load_model()
|
|
161
|
+
out_rows: list[dict[str, Any]] = []
|
|
162
|
+
for _, row in batch.iterrows():
|
|
163
|
+
row_dict = row.to_dict()
|
|
164
|
+
doc = Document(
|
|
165
|
+
document_id=row_dict.get("document_id") or str(uuid.uuid4()),
|
|
166
|
+
raw_content=str(row_dict.get("raw_content", "")),
|
|
167
|
+
metadata=dict(row_dict.get("metadata") or {}),
|
|
168
|
+
tags=dict(row_dict.get("tags") or {}),
|
|
169
|
+
)
|
|
170
|
+
enriched = self.process_document(doc)
|
|
171
|
+
row_dict["document_id"] = enriched.document_id
|
|
172
|
+
row_dict["raw_content"] = enriched.raw_content
|
|
173
|
+
row_dict["metadata"] = enriched.metadata
|
|
174
|
+
row_dict["tags"] = enriched.tags
|
|
175
|
+
out_rows.append(row_dict)
|
|
176
|
+
return pd.DataFrame(out_rows)
|
|
177
|
+
|
|
178
|
+
# ------------------------------------------------------------------
|
|
179
|
+
# Config validation
|
|
180
|
+
# ------------------------------------------------------------------
|
|
181
|
+
|
|
182
|
+
def validate_config(self) -> None:
|
|
183
|
+
"""Verify that the tagger's parameters are sane.
|
|
184
|
+
|
|
185
|
+
The default implementation performs no checks. Override to
|
|
186
|
+
enforce domain-specific constraints and raise :class:`ValueError`.
|
|
187
|
+
"""
|
|
188
|
+
return None
|
|
189
|
+
|
|
190
|
+
# ------------------------------------------------------------------
|
|
191
|
+
# Resource management
|
|
192
|
+
# ------------------------------------------------------------------
|
|
193
|
+
|
|
194
|
+
def load_model(self) -> None:
|
|
195
|
+
"""Load heavy model weights into memory.
|
|
196
|
+
|
|
197
|
+
This hook is called by the Ray runner immediately before the tagger
|
|
198
|
+
is used to process a shard (SDMI) or when the actor starts (SIMD).
|
|
199
|
+
Implementations should override this to perform deferred initialization.
|
|
200
|
+
"""
|
|
201
|
+
return None
|
|
202
|
+
|
|
203
|
+
def unload_model(self) -> None:
|
|
204
|
+
"""Unload model weights and clear memory.
|
|
205
|
+
|
|
206
|
+
This hook is called by the Ray runner in SDMI mode after a shard is
|
|
207
|
+
fully processed by this tagger to ensure memory is cleared before
|
|
208
|
+
loading the next tagger.
|
|
209
|
+
"""
|
|
210
|
+
return None
|
|
211
|
+
|
|
212
|
+
# ------------------------------------------------------------------
|
|
213
|
+
# Resource requirements
|
|
214
|
+
# ------------------------------------------------------------------
|
|
215
|
+
|
|
216
|
+
@property
|
|
217
|
+
def resources(self) -> dict[str, int]:
|
|
218
|
+
"""Return Ray resource requirements for ``map_batches``.
|
|
219
|
+
|
|
220
|
+
Returns ``{"num_cpus": ..., "num_gpus": ...}``.
|
|
221
|
+
"""
|
|
222
|
+
return {"num_cpus": 1, "num_gpus": 0}
|
|
223
|
+
|
|
224
|
+
@property
|
|
225
|
+
def use_actors(self) -> bool:
|
|
226
|
+
"""Whether Ray should use ``ActorPoolStrategy`` for this tagger.
|
|
227
|
+
|
|
228
|
+
Defaults to ``False``. GPU taggers override to ``True`` so that
|
|
229
|
+
heavy models stay loaded across batches.
|
|
230
|
+
"""
|
|
231
|
+
return False
|
|
232
|
+
|
|
233
|
+
# ------------------------------------------------------------------
|
|
234
|
+
# Utilities
|
|
235
|
+
# ------------------------------------------------------------------
|
|
236
|
+
|
|
237
|
+
@property
|
|
238
|
+
def name(self) -> str:
|
|
239
|
+
"""Return the tagger's canonical name from its config."""
|
|
240
|
+
return self.config.tagger_name
|
|
241
|
+
|
|
242
|
+
def __repr__(self) -> str:
|
|
243
|
+
"""Return a string representation of the tagger."""
|
|
244
|
+
return f"{self.__class__.__name__}(name={self.name!r})"
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
class CPUTagger(BaseTagger, ABC):
|
|
248
|
+
"""Base for taggers that execute exclusively on CPU."""
|
|
249
|
+
|
|
250
|
+
resource_type: str = "cpu"
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
class GPUTagger(BaseTagger, ABC):
|
|
254
|
+
"""Base for taggers that require GPU resources.
|
|
255
|
+
|
|
256
|
+
Uses ``ActorPoolStrategy`` by default so that large models remain
|
|
257
|
+
loaded in GPU memory across batches.
|
|
258
|
+
"""
|
|
259
|
+
|
|
260
|
+
resource_type: str = "gpu"
|
|
261
|
+
|
|
262
|
+
@property
|
|
263
|
+
def resources(self) -> dict[str, int]:
|
|
264
|
+
"""Request 1 CPU + 1 GPU."""
|
|
265
|
+
return {"num_cpus": 1, "num_gpus": 1}
|
|
266
|
+
|
|
267
|
+
@property
|
|
268
|
+
def use_actors(self) -> bool:
|
|
269
|
+
"""GPU taggers use actors to keep models warm."""
|
|
270
|
+
return True
|