gradiend 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.
- gradiend/__init__.py +103 -0
- gradiend/data/__init__.py +23 -0
- gradiend/data/core/__init__.py +7 -0
- gradiend/data/core/base_loader.py +121 -0
- gradiend/data/core/spacy_util.py +63 -0
- gradiend/data/text/__init__.py +16 -0
- gradiend/data/text/filter_config.py +93 -0
- gradiend/data/text/prediction/__init__.py +10 -0
- gradiend/data/text/prediction/creator.py +771 -0
- gradiend/data/text/prediction/filter_engine.py +359 -0
- gradiend/data/text/preprocess.py +241 -0
- gradiend/evaluator/__init__.py +22 -0
- gradiend/evaluator/config.py +30 -0
- gradiend/evaluator/decoder.py +951 -0
- gradiend/evaluator/decoder_eval_utils.py +55 -0
- gradiend/evaluator/encoder.py +243 -0
- gradiend/evaluator/encoder_metrics.py +398 -0
- gradiend/evaluator/evaluator.py +280 -0
- gradiend/model/__init__.py +14 -0
- gradiend/model/core/__init__.py +17 -0
- gradiend/model/core/backbone.py +236 -0
- gradiend/model/layers.py +129 -0
- gradiend/model/model.py +791 -0
- gradiend/model/model_with_gradiend.py +890 -0
- gradiend/model/param_mapped.py +916 -0
- gradiend/model/utils.py +376 -0
- gradiend/py.typed +0 -0
- gradiend/trainer/__init__.py +70 -0
- gradiend/trainer/config.py +25 -0
- gradiend/trainer/core/__init__.py +23 -0
- gradiend/trainer/core/arguments.py +335 -0
- gradiend/trainer/core/callbacks.py +473 -0
- gradiend/trainer/core/config.py +15 -0
- gradiend/trainer/core/dataset.py +215 -0
- gradiend/trainer/core/feature_definition.py +672 -0
- gradiend/trainer/core/protocols.py +65 -0
- gradiend/trainer/core/pruning.py +385 -0
- gradiend/trainer/core/stats.py +152 -0
- gradiend/trainer/core/training.py +549 -0
- gradiend/trainer/factory.py +80 -0
- gradiend/trainer/text/__init__.py +36 -0
- gradiend/trainer/text/common/__init__.py +21 -0
- gradiend/trainer/text/common/dataset.py +51 -0
- gradiend/trainer/text/common/dataset_base.py +148 -0
- gradiend/trainer/text/common/lm_eval.py +505 -0
- gradiend/trainer/text/common/loading.py +140 -0
- gradiend/trainer/text/common/model_base.py +97 -0
- gradiend/trainer/text/prediction/__init__.py +19 -0
- gradiend/trainer/text/prediction/dataset.py +237 -0
- gradiend/trainer/text/prediction/decoder_eval_utils.py +392 -0
- gradiend/trainer/text/prediction/decoder_only_mlm.py +405 -0
- gradiend/trainer/text/prediction/model_with_gradiend.py +184 -0
- gradiend/trainer/text/prediction/trainer.py +2199 -0
- gradiend/trainer/text/prediction/unified_data.py +680 -0
- gradiend/trainer/text/prediction/unified_schema.py +26 -0
- gradiend/trainer/trainer.py +1668 -0
- gradiend/util/__init__.py +2 -0
- gradiend/util/logging.py +91 -0
- gradiend/util/metrics.py +191 -0
- gradiend/util/paths.py +373 -0
- gradiend/util/util.py +121 -0
- gradiend/visualizer/__init__.py +30 -0
- gradiend/visualizer/convergence.py +559 -0
- gradiend/visualizer/encoder_distributions.py +535 -0
- gradiend/visualizer/encoder_scatter.py +248 -0
- gradiend/visualizer/plot_optional.py +35 -0
- gradiend/visualizer/probability_shifts.py +373 -0
- gradiend/visualizer/topk/__init__.py +26 -0
- gradiend/visualizer/topk/pairwise_heatmap.py +621 -0
- gradiend/visualizer/topk/venn_.py +298 -0
- gradiend/visualizer/visualizer.py +99 -0
- gradiend-0.1.0.dist-info/METADATA +130 -0
- gradiend-0.1.0.dist-info/RECORD +76 -0
- gradiend-0.1.0.dist-info/WHEEL +5 -0
- gradiend-0.1.0.dist-info/licenses/LICENSE +201 -0
- gradiend-0.1.0.dist-info/top_level.txt +1 -0
gradiend/__init__.py
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""
|
|
2
|
+
GRADIEND: Feature Learning within Neural Networks
|
|
3
|
+
|
|
4
|
+
GRADIEND is a method for learning features within neural networks
|
|
5
|
+
by training an encoder-decoder architecture on gradients.
|
|
6
|
+
|
|
7
|
+
Public API (from gradiend):
|
|
8
|
+
- Model: GradiendModel, ParamMappedGradiendModel, ModelWithGradiend
|
|
9
|
+
- Data: TextFilterConfig, TextPredictionDataCreator, TextPreprocessConfig,
|
|
10
|
+
SpacyTagSpec, preprocess_texts, resolve_base_data
|
|
11
|
+
- Trainer: TextPredictionTrainer, TextPredictionConfig, TrainingArguments,
|
|
12
|
+
load_training_stats, GradientTrainingDataset, TextGradientTrainingDataset,
|
|
13
|
+
create_model_with_gradiend
|
|
14
|
+
- Logging: setup_logging, get_logger
|
|
15
|
+
|
|
16
|
+
Sub-packages (use when you need modality-specific or internal APIs):
|
|
17
|
+
- gradiend.trainer: Trainer, PrePruneConfig, PostPruneConfig, callbacks, etc.
|
|
18
|
+
- gradiend.trainer.text: TextModelWithGradiend, TextBatchedDataset, etc.
|
|
19
|
+
- gradiend.evaluator: EncoderEvaluator, DecoderEvaluator, Evaluator
|
|
20
|
+
- gradiend.visualizer: Visualizer, plot_encoder_distributions, plot_topk_overlap_heatmap, plot_topk_overlap_venn, etc.
|
|
21
|
+
- gradiend.data: same as top-level data API (alternative import path)
|
|
22
|
+
|
|
23
|
+
For experimental features (analysis, plotting, LaTeX export), install with:
|
|
24
|
+
pip install gradiend[recommended]
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
28
|
+
|
|
29
|
+
try:
|
|
30
|
+
__version__ = version("gradiend")
|
|
31
|
+
except PackageNotFoundError:
|
|
32
|
+
__version__ = "0.1.0" # editable install before package is installed
|
|
33
|
+
|
|
34
|
+
# Core model classes
|
|
35
|
+
from gradiend.model import GradiendModel, ParamMappedGradiendModel, ModelWithGradiend
|
|
36
|
+
|
|
37
|
+
# High-level data API (filter config, data creator, preprocess)
|
|
38
|
+
from gradiend.data import (
|
|
39
|
+
TextFilterConfig,
|
|
40
|
+
TextPredictionDataCreator,
|
|
41
|
+
TextPreprocessConfig,
|
|
42
|
+
SpacyTagSpec,
|
|
43
|
+
preprocess_texts,
|
|
44
|
+
resolve_base_data,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# Text prediction trainer (high-level)
|
|
48
|
+
from gradiend.trainer.text.prediction.trainer import TextPredictionTrainer, TextPredictionConfig
|
|
49
|
+
|
|
50
|
+
# Logging
|
|
51
|
+
from gradiend.util.logging import setup_logging, get_logger
|
|
52
|
+
|
|
53
|
+
# Visualization (top-k overlap plots)
|
|
54
|
+
from gradiend.visualizer import (
|
|
55
|
+
plot_topk_overlap_heatmap,
|
|
56
|
+
plot_topk_overlap_venn,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# Training
|
|
60
|
+
from gradiend.trainer import (
|
|
61
|
+
load_training_stats,
|
|
62
|
+
set_seed,
|
|
63
|
+
TrainingArguments,
|
|
64
|
+
TrainerConfig,
|
|
65
|
+
GradientTrainingDataset,
|
|
66
|
+
TextGradientTrainingDataset,
|
|
67
|
+
create_model_with_gradiend,
|
|
68
|
+
PrePruneConfig,
|
|
69
|
+
PostPruneConfig
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
__all__ = [
|
|
73
|
+
# Core model
|
|
74
|
+
"GradiendModel",
|
|
75
|
+
"ParamMappedGradiendModel",
|
|
76
|
+
"ModelWithGradiend",
|
|
77
|
+
# Data (high-level)
|
|
78
|
+
"TextFilterConfig",
|
|
79
|
+
"TextPredictionDataCreator",
|
|
80
|
+
"TextPreprocessConfig",
|
|
81
|
+
"SpacyTagSpec",
|
|
82
|
+
"preprocess_texts",
|
|
83
|
+
"resolve_base_data",
|
|
84
|
+
# Trainers and configs
|
|
85
|
+
"TextPredictionTrainer",
|
|
86
|
+
"TextPredictionConfig",
|
|
87
|
+
"TrainerConfig",
|
|
88
|
+
"PrePruneConfig",
|
|
89
|
+
"PostPruneConfig",
|
|
90
|
+
# Logging
|
|
91
|
+
"setup_logging",
|
|
92
|
+
"get_logger",
|
|
93
|
+
# Training
|
|
94
|
+
"load_training_stats",
|
|
95
|
+
"set_seed",
|
|
96
|
+
"TrainingArguments",
|
|
97
|
+
"GradientTrainingDataset",
|
|
98
|
+
"TextGradientTrainingDataset",
|
|
99
|
+
"create_model_with_gradiend",
|
|
100
|
+
# Visualization
|
|
101
|
+
"plot_topk_overlap_heatmap",
|
|
102
|
+
"plot_topk_overlap_venn",
|
|
103
|
+
]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Data module: create training and neutral datasets from base corpora.
|
|
3
|
+
|
|
4
|
+
Use TextPredictionDataCreator to filter and mask base texts based on TextFilterConfig.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from gradiend.data.core import resolve_base_data
|
|
8
|
+
from gradiend.data.text import (
|
|
9
|
+
SpacyTagSpec,
|
|
10
|
+
TextFilterConfig,
|
|
11
|
+
TextPreprocessConfig,
|
|
12
|
+
preprocess_texts,
|
|
13
|
+
)
|
|
14
|
+
from gradiend.data.text.prediction import TextPredictionDataCreator
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"SpacyTagSpec",
|
|
18
|
+
"TextFilterConfig",
|
|
19
|
+
"TextPreprocessConfig",
|
|
20
|
+
"TextPredictionDataCreator",
|
|
21
|
+
"preprocess_texts",
|
|
22
|
+
"resolve_base_data",
|
|
23
|
+
]
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base data loader: resolve from HF, DataFrame, CSV, or list of strings.
|
|
3
|
+
|
|
4
|
+
Modality-agnostic; used by both text prediction and (future) classification.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import random
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import List, Optional, Union
|
|
12
|
+
|
|
13
|
+
import pandas as pd
|
|
14
|
+
|
|
15
|
+
from gradiend.util.logging import get_logger
|
|
16
|
+
|
|
17
|
+
logger = get_logger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def resolve_base_data(
|
|
21
|
+
source: Union[str, pd.DataFrame, List[str]],
|
|
22
|
+
text_column: str = "text",
|
|
23
|
+
max_size: Optional[int] = None,
|
|
24
|
+
split: str = "train",
|
|
25
|
+
seed: int = 42,
|
|
26
|
+
hf_config: Optional[str] = None,
|
|
27
|
+
trust_remote_code: bool = False,
|
|
28
|
+
) -> List[str]:
|
|
29
|
+
"""Resolve input to a list of text strings.
|
|
30
|
+
|
|
31
|
+
Supports HuggingFace dataset ID, pandas DataFrame, CSV path, or list of strings.
|
|
32
|
+
Data is shuffled with `seed` before applying `max_size` to avoid bias from
|
|
33
|
+
ordered sources (e.g. chronological, single-author).
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
source: HF dataset ID (str), CSV path (str ending in .csv or path exists),
|
|
37
|
+
pandas DataFrame, or List[str].
|
|
38
|
+
text_column: Column name for text (default "text"). Ignored for List[str].
|
|
39
|
+
max_size: Cap on number of items (applied after shuffle). None = no cap.
|
|
40
|
+
split: Dataset split for HF (default "train").
|
|
41
|
+
seed: Random seed for shuffle.
|
|
42
|
+
hf_config: HuggingFace dataset config/subset (e.g. "20220301.en" for wikipedia).
|
|
43
|
+
Only used when source is an HF dataset ID.
|
|
44
|
+
trust_remote_code: Passed to load_dataset when loading from HF. Default False.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
List of strings (texts).
|
|
48
|
+
"""
|
|
49
|
+
if not isinstance(text_column, str):
|
|
50
|
+
raise TypeError(f"text_column must be str, got {type(text_column).__name__}")
|
|
51
|
+
if max_size is not None and not isinstance(max_size, int):
|
|
52
|
+
raise TypeError(f"max_size must be int or None, got {type(max_size).__name__}")
|
|
53
|
+
if not isinstance(split, str):
|
|
54
|
+
raise TypeError(f"split must be str, got {type(split).__name__}")
|
|
55
|
+
if not isinstance(seed, int):
|
|
56
|
+
raise TypeError(f"seed must be int, got {type(seed).__name__}")
|
|
57
|
+
if hf_config is not None and not isinstance(hf_config, str):
|
|
58
|
+
raise TypeError(f"hf_config must be str or None, got {type(hf_config).__name__}")
|
|
59
|
+
if not isinstance(trust_remote_code, bool):
|
|
60
|
+
raise TypeError(f"trust_remote_code must be bool, got {type(trust_remote_code).__name__}")
|
|
61
|
+
|
|
62
|
+
texts: List[str]
|
|
63
|
+
if isinstance(source, list):
|
|
64
|
+
if not all(isinstance(x, str) for x in source):
|
|
65
|
+
raise TypeError("source as list must contain only strings")
|
|
66
|
+
texts = [str(x).strip() for x in source if str(x).strip()]
|
|
67
|
+
elif isinstance(source, pd.DataFrame):
|
|
68
|
+
if text_column not in source.columns:
|
|
69
|
+
raise ValueError(f"DataFrame missing column '{text_column}'. Columns: {list(source.columns)}")
|
|
70
|
+
texts = source[text_column].dropna().astype(str).str.strip().tolist()
|
|
71
|
+
texts = [x for x in texts if x]
|
|
72
|
+
elif isinstance(source, str):
|
|
73
|
+
texts = _load_from_string_source(
|
|
74
|
+
source, text_column, split, hf_config, trust_remote_code
|
|
75
|
+
)
|
|
76
|
+
else:
|
|
77
|
+
raise TypeError(f"source must be str, DataFrame, or List[str]; got {type(source)}")
|
|
78
|
+
|
|
79
|
+
rng = random.Random(seed)
|
|
80
|
+
rng.shuffle(texts)
|
|
81
|
+
if max_size is not None and len(texts) > max_size:
|
|
82
|
+
texts = texts[:max_size]
|
|
83
|
+
logger.debug(f"resolve_base_data: {len(texts)} texts")
|
|
84
|
+
return texts
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _load_from_string_source(
|
|
88
|
+
source: str,
|
|
89
|
+
text_column: str,
|
|
90
|
+
split: str,
|
|
91
|
+
hf_config: Optional[str] = None,
|
|
92
|
+
trust_remote_code: bool = False,
|
|
93
|
+
) -> List[str]:
|
|
94
|
+
"""Load from HF dataset or CSV path."""
|
|
95
|
+
path = Path(source)
|
|
96
|
+
if path.suffix.lower() == ".csv" and path.exists():
|
|
97
|
+
df = pd.read_csv(source)
|
|
98
|
+
if text_column not in df.columns:
|
|
99
|
+
raise ValueError(f"CSV missing column '{text_column}'. Columns: {list(df.columns)}")
|
|
100
|
+
texts = df[text_column].dropna().astype(str).str.strip().tolist()
|
|
101
|
+
return [x for x in texts if x]
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
from datasets import load_dataset
|
|
105
|
+
except ImportError as e:
|
|
106
|
+
raise ImportError("HuggingFace datasets required for HF source. pip install datasets") from e
|
|
107
|
+
|
|
108
|
+
if hf_config is not None:
|
|
109
|
+
ds = load_dataset(
|
|
110
|
+
source, hf_config, split=split, trust_remote_code=trust_remote_code
|
|
111
|
+
)
|
|
112
|
+
else:
|
|
113
|
+
ds = load_dataset(source, split=split, trust_remote_code=trust_remote_code)
|
|
114
|
+
if hasattr(ds, "to_pandas"):
|
|
115
|
+
df = ds.to_pandas()
|
|
116
|
+
else:
|
|
117
|
+
df = pd.DataFrame(list(ds))
|
|
118
|
+
if text_column not in df.columns:
|
|
119
|
+
raise ValueError(f"HF dataset missing column '{text_column}'. Columns: {list(df.columns)}")
|
|
120
|
+
texts = df[text_column].dropna().astype(str).str.strip().tolist()
|
|
121
|
+
return [x for x in texts if x]
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Spacy model loading with clearer errors and optional auto-download.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
# Spacy model-not-found error code
|
|
10
|
+
_SPACY_E050 = "E050"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def load_spacy_model(
|
|
14
|
+
model_name: str,
|
|
15
|
+
download_if_missing: bool = False,
|
|
16
|
+
) -> Any:
|
|
17
|
+
"""Load a spacy model with improved error handling.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
model_name: Spacy model name (e.g. "de_core_news_sm").
|
|
21
|
+
download_if_missing: If True and the model is not found, attempt to
|
|
22
|
+
download it via `python -m spacy download`. Default False.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
Loaded spacy Language model.
|
|
26
|
+
|
|
27
|
+
Raises:
|
|
28
|
+
ImportError: If spacy is not installed.
|
|
29
|
+
OSError: If the model is not found, with a message including the
|
|
30
|
+
install command: "python -m spacy download {model_name}".
|
|
31
|
+
"""
|
|
32
|
+
try:
|
|
33
|
+
import spacy
|
|
34
|
+
except ImportError as e:
|
|
35
|
+
raise ImportError(
|
|
36
|
+
"spacy is required for morphological filtering. "
|
|
37
|
+
"Install with: pip install spacy "
|
|
38
|
+
"Or: pip install gradiend[data]"
|
|
39
|
+
) from e
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
return spacy.load(model_name)
|
|
43
|
+
except OSError as e:
|
|
44
|
+
err_str = str(e)
|
|
45
|
+
is_model_not_found = _SPACY_E050 in err_str or "Can't find model" in err_str
|
|
46
|
+
|
|
47
|
+
if is_model_not_found and download_if_missing:
|
|
48
|
+
try:
|
|
49
|
+
from spacy.cli import download
|
|
50
|
+
download(model_name)
|
|
51
|
+
return spacy.load(model_name)
|
|
52
|
+
except Exception as download_err:
|
|
53
|
+
raise OSError(
|
|
54
|
+
f"Spacy model '{model_name}' not found and auto-download failed: {download_err}. "
|
|
55
|
+
f"Install manually with: python -m spacy download {model_name}"
|
|
56
|
+
) from e
|
|
57
|
+
|
|
58
|
+
if is_model_not_found:
|
|
59
|
+
raise OSError(
|
|
60
|
+
f"Spacy model '{model_name}' not found. "
|
|
61
|
+
f"Install it with: python -m spacy download {model_name}"
|
|
62
|
+
) from e
|
|
63
|
+
raise
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Text-specific data modules."""
|
|
2
|
+
|
|
3
|
+
from gradiend.data.text.filter_config import SpacyTagSpec, TextFilterConfig
|
|
4
|
+
from gradiend.data.text.preprocess import (
|
|
5
|
+
TextPreprocessConfig,
|
|
6
|
+
iter_sentences_from_texts,
|
|
7
|
+
preprocess_texts,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"SpacyTagSpec",
|
|
12
|
+
"TextFilterConfig",
|
|
13
|
+
"TextPreprocessConfig",
|
|
14
|
+
"iter_sentences_from_texts",
|
|
15
|
+
"preprocess_texts",
|
|
16
|
+
]
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Filter configuration for text: targets, spacy tags, lemma matching.
|
|
3
|
+
|
|
4
|
+
Not prediction-specific; used by text filtering in general.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass, field
|
|
10
|
+
from typing import Dict, List, Optional, Union
|
|
11
|
+
|
|
12
|
+
# Type alias for spacy morph/tag constraints (e.g. {"pos": "DET", "Case": "Nom"})
|
|
13
|
+
SpacyTagSpec = Dict[str, str]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _merge_spacy_tags(parent: Optional[SpacyTagSpec], child: Optional[SpacyTagSpec]) -> Optional[SpacyTagSpec]:
|
|
17
|
+
"""Merge child tags into parent; child overrides parent for same keys."""
|
|
18
|
+
if parent is None and child is None:
|
|
19
|
+
return None
|
|
20
|
+
if parent is None:
|
|
21
|
+
return dict(child) if child else None
|
|
22
|
+
if child is None:
|
|
23
|
+
return dict(parent)
|
|
24
|
+
out = dict(parent)
|
|
25
|
+
out.update(child)
|
|
26
|
+
return out
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _first_target_string(targets: List[Union["TextFilterConfig", str]]) -> Optional[str]:
|
|
30
|
+
"""Extract first target string from targets for default id."""
|
|
31
|
+
for t in targets:
|
|
32
|
+
if isinstance(t, str):
|
|
33
|
+
return t
|
|
34
|
+
if isinstance(t, TextFilterConfig):
|
|
35
|
+
s = _first_target_string(t.targets)
|
|
36
|
+
if s is not None:
|
|
37
|
+
return s
|
|
38
|
+
return None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass
|
|
42
|
+
class TextFilterConfig:
|
|
43
|
+
"""Configuration for filtering and masking target tokens in text.
|
|
44
|
+
|
|
45
|
+
Simple use: TextFilterConfig(target="das") or TextFilterConfig(targets=["der", "die"], spacy_tags={...})
|
|
46
|
+
Advanced: TextFilterConfig(targets=[TextFilterConfig(["das"], spacy_tags={...}), "der"], spacy_tags={...})
|
|
47
|
+
Nested entries inherit parent spacy_tags and may add/override their own.
|
|
48
|
+
|
|
49
|
+
When used in TextPredictionDataCreator.feature_targets (a list), id names the output class.
|
|
50
|
+
If id is None, it is inferred from the first target string.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
targets: Optional[List[Union["TextFilterConfig", str]]] = None
|
|
54
|
+
target: Optional[str] = None
|
|
55
|
+
spacy_tags: Optional[SpacyTagSpec] = None
|
|
56
|
+
use_lemma: bool = False
|
|
57
|
+
id: Optional[str] = None
|
|
58
|
+
mask: str = "[MASK]"
|
|
59
|
+
weight: float = 1.0
|
|
60
|
+
|
|
61
|
+
def __post_init__(self) -> None:
|
|
62
|
+
if self.target is not None and self.targets is not None:
|
|
63
|
+
raise ValueError("TextFilterConfig: provide either target or targets, not both")
|
|
64
|
+
if self.target is not None:
|
|
65
|
+
self.targets = [self.target]
|
|
66
|
+
elif isinstance(self.targets, str):
|
|
67
|
+
self.targets = [self.targets]
|
|
68
|
+
if self.targets is None:
|
|
69
|
+
self.targets = []
|
|
70
|
+
if not self.targets:
|
|
71
|
+
raise ValueError("TextFilterConfig.targets must be non-empty")
|
|
72
|
+
if self.id is None:
|
|
73
|
+
self.id = _first_target_string(self.targets)
|
|
74
|
+
|
|
75
|
+
def get_effective_tags(self, parent_tags: Optional[SpacyTagSpec] = None) -> Optional[SpacyTagSpec]:
|
|
76
|
+
"""Get merged spacy_tags (self + parent)."""
|
|
77
|
+
return _merge_spacy_tags(parent_tags, self.spacy_tags)
|
|
78
|
+
|
|
79
|
+
def flatten_targets_with_tags(
|
|
80
|
+
self,
|
|
81
|
+
parent_tags: Optional[SpacyTagSpec] = None,
|
|
82
|
+
) -> List[tuple[str, Optional[SpacyTagSpec]]]:
|
|
83
|
+
"""Flatten nested config to list of (target_str, effective_spacy_tags)."""
|
|
84
|
+
effective = self.get_effective_tags(parent_tags)
|
|
85
|
+
out: List[tuple[str, Optional[SpacyTagSpec]]] = []
|
|
86
|
+
for t in self.targets:
|
|
87
|
+
if isinstance(t, str):
|
|
88
|
+
out.append((t, effective))
|
|
89
|
+
elif isinstance(t, TextFilterConfig):
|
|
90
|
+
out.extend(t.flatten_targets_with_tags(effective))
|
|
91
|
+
else:
|
|
92
|
+
raise TypeError(f"target must be str or TextFilterConfig; got {type(t)}")
|
|
93
|
+
return out
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""Text prediction data: filter engine, TextPredictionDataCreator."""
|
|
2
|
+
|
|
3
|
+
from gradiend.data.text.prediction.creator import TextPredictionDataCreator
|
|
4
|
+
from gradiend.data.text.prediction.filter_engine import filter_sentences, mask_sentence
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"filter_sentences",
|
|
8
|
+
"mask_sentence",
|
|
9
|
+
"TextPredictionDataCreator",
|
|
10
|
+
]
|