kcai-data-sampling-fgsm 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (21) hide show
  1. kcai_data_sampling_fgsm-0.1.0/PKG-INFO +111 -0
  2. kcai_data_sampling_fgsm-0.1.0/README.md +93 -0
  3. kcai_data_sampling_fgsm-0.1.0/pyproject.toml +41 -0
  4. kcai_data_sampling_fgsm-0.1.0/requirements.txt +1 -0
  5. kcai_data_sampling_fgsm-0.1.0/setup.cfg +4 -0
  6. kcai_data_sampling_fgsm-0.1.0/src/kcai_data_sampling_fgsm/__init__.py +12 -0
  7. kcai_data_sampling_fgsm-0.1.0/src/kcai_data_sampling_fgsm/_version_.py +24 -0
  8. kcai_data_sampling_fgsm-0.1.0/src/kcai_data_sampling_fgsm/api/__init__.py +7 -0
  9. kcai_data_sampling_fgsm-0.1.0/src/kcai_data_sampling_fgsm/api/transformations/__init__.py +10 -0
  10. kcai_data_sampling_fgsm-0.1.0/src/kcai_data_sampling_fgsm/api/transformations/fgsm.py +68 -0
  11. kcai_data_sampling_fgsm-0.1.0/src/kcai_data_sampling_fgsm/configs.py +57 -0
  12. kcai_data_sampling_fgsm-0.1.0/src/kcai_data_sampling_fgsm/py.typed +0 -0
  13. kcai_data_sampling_fgsm-0.1.0/src/kcai_data_sampling_fgsm/transformations/__init__.py +11 -0
  14. kcai_data_sampling_fgsm-0.1.0/src/kcai_data_sampling_fgsm/transformations/fgsm.py +40 -0
  15. kcai_data_sampling_fgsm-0.1.0/src/kcai_data_sampling_fgsm.egg-info/PKG-INFO +111 -0
  16. kcai_data_sampling_fgsm-0.1.0/src/kcai_data_sampling_fgsm.egg-info/SOURCES.txt +19 -0
  17. kcai_data_sampling_fgsm-0.1.0/src/kcai_data_sampling_fgsm.egg-info/dependency_links.txt +1 -0
  18. kcai_data_sampling_fgsm-0.1.0/src/kcai_data_sampling_fgsm.egg-info/entry_points.txt +2 -0
  19. kcai_data_sampling_fgsm-0.1.0/src/kcai_data_sampling_fgsm.egg-info/requires.txt +1 -0
  20. kcai_data_sampling_fgsm-0.1.0/src/kcai_data_sampling_fgsm.egg-info/scm_file_list.json +15 -0
  21. kcai_data_sampling_fgsm-0.1.0/src/kcai_data_sampling_fgsm.egg-info/top_level.txt +1 -0
@@ -0,0 +1,111 @@
1
+ Metadata-Version: 2.4
2
+ Name: kcai-data-sampling-fgsm
3
+ Version: 0.1.0
4
+ Summary: Adversarial perturbation (FGSM) for kcai data-sampling
5
+ Author-email: Safenai <support@safenai.io>
6
+ License-Expression: Apache-2.0
7
+ Keywords: ml,data,augmentation,robustness,adversarial,fgsm
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
15
+ Requires-Python: >=3.11
16
+ Description-Content-Type: text/markdown
17
+ Requires-Dist: kcai-data-sampling-core
18
+
19
+ # kcai-data-sampling-fgsm
20
+
21
+ The **adversarial** slot of kcai data-sampling: transformations where a model's
22
+ *response* enters the computation and the result is graded against it. Here the
23
+ model is a **target** — it is not asked to produce anything, only to react. That
24
+ is what makes the family adversarial, and the declaring `model_role = "target"`
25
+ is what tells the framework to treat it as such.
26
+
27
+ This package implements the Fast Gradient Sign Method as a single budgeted step
28
+ along the sign of the target model's gradient, and exposes it through the
29
+ `kcai_data_sampling.transformations` entry-point group.
30
+
31
+ **The target model is yours.** It arrives at run time through the `models:`
32
+ section of your configuration and is never shipped by this package.
33
+
34
+ ## What it ships today
35
+
36
+ - `fgsm` — one method: one L-infinity step of budget `epsilon` along the sign of
37
+ the target's gradient.
38
+
39
+ One method, as an example of the slot rather than a catalogue.
40
+
41
+ ## Install
42
+
43
+ ```bash
44
+ pip install "kcai-data-sampling[fgsm]"
45
+ ```
46
+
47
+ **No deep-learning framework is required.** This package depends only on the
48
+ core contracts — the gradient arrives from *your* model, so the work is yours
49
+ too, and nothing here pulls torch. A configuration driving `fgsm` may well need
50
+ torch in the environment that hosts the target model; that is a property of the
51
+ model you bring, not of this package.
52
+
53
+ ## How the step works
54
+
55
+ The batch is normalized to `[0, 1]` pixel units, the target's gradient is taken
56
+ in the same units, and `epsilon * sign(grad)` is added — so only the *sign* of
57
+ the gradient participates, not its magnitude. The result is clipped back into
58
+ range and restored to the batch's dtype.
59
+
60
+ Three declarations follow from that, and the framework enforces each:
61
+
62
+ - **`clips = True`** — a signed step can push a pixel past the selection's value
63
+ range, so the output is clipped back rather than refused.
64
+ - **`reversible = False`** — the step is lossy. The original pixels are not
65
+ recoverable from the output, so the row records that it is not invertible.
66
+ - **Deterministic** — no randomness is drawn, so the recorded seed is `None`.
67
+ The same input and the same `epsilon` always give the same output.
68
+
69
+ `epsilon` is the adversarial budget, strictly positive, and sweepable, so a run
70
+ can walk a whole budget curve.
71
+
72
+ ## Labels do not move
73
+
74
+ An attack moves the model's *prediction*, not the truth. The ground-truth label
75
+ belongs to the source row, travels with it, and is never touched here — this
76
+ package has no notion of a label at all, only of pixels.
77
+
78
+ That is what makes an adversarial sample meaningful: if the label had moved
79
+ along with the pixels, the pair would prove nothing. A label that changed under
80
+ perturbation, or a target model whose response was ignored, would both mean the
81
+ measurement was not an attack at all.
82
+
83
+ ## Example
84
+
85
+ The `models` and `operations` sections of a job configuration, with a target
86
+ model supplied as your own source:
87
+
88
+ ```yaml
89
+ models:
90
+ yolo:
91
+ type: python
92
+ path: adapters/yolo_target.py
93
+ export: YoloTarget
94
+ weights: yolov8n.pt
95
+ params: { conf: 0.25 }
96
+ operations:
97
+ transformations:
98
+ - name: fgsm
99
+ type: fgsm
100
+ target_model: yolo
101
+ epsilon:
102
+ range: [0.01, 0.05]
103
+ step: 0.01
104
+ ```
105
+
106
+ The transformation names its model with `target_model: yolo`. Only `grad` is
107
+ used from it, and its output is checked for shape and finiteness before the step,
108
+ so a misbehaving adapter fails loudly rather than corrupting the batch.
109
+
110
+ A target model is recognised by a non-empty `name` plus a `grad` method, and
111
+ conformance is checked against the `target` role the transformation declares.
@@ -0,0 +1,93 @@
1
+ # kcai-data-sampling-fgsm
2
+
3
+ The **adversarial** slot of kcai data-sampling: transformations where a model's
4
+ *response* enters the computation and the result is graded against it. Here the
5
+ model is a **target** — it is not asked to produce anything, only to react. That
6
+ is what makes the family adversarial, and the declaring `model_role = "target"`
7
+ is what tells the framework to treat it as such.
8
+
9
+ This package implements the Fast Gradient Sign Method as a single budgeted step
10
+ along the sign of the target model's gradient, and exposes it through the
11
+ `kcai_data_sampling.transformations` entry-point group.
12
+
13
+ **The target model is yours.** It arrives at run time through the `models:`
14
+ section of your configuration and is never shipped by this package.
15
+
16
+ ## What it ships today
17
+
18
+ - `fgsm` — one method: one L-infinity step of budget `epsilon` along the sign of
19
+ the target's gradient.
20
+
21
+ One method, as an example of the slot rather than a catalogue.
22
+
23
+ ## Install
24
+
25
+ ```bash
26
+ pip install "kcai-data-sampling[fgsm]"
27
+ ```
28
+
29
+ **No deep-learning framework is required.** This package depends only on the
30
+ core contracts — the gradient arrives from *your* model, so the work is yours
31
+ too, and nothing here pulls torch. A configuration driving `fgsm` may well need
32
+ torch in the environment that hosts the target model; that is a property of the
33
+ model you bring, not of this package.
34
+
35
+ ## How the step works
36
+
37
+ The batch is normalized to `[0, 1]` pixel units, the target's gradient is taken
38
+ in the same units, and `epsilon * sign(grad)` is added — so only the *sign* of
39
+ the gradient participates, not its magnitude. The result is clipped back into
40
+ range and restored to the batch's dtype.
41
+
42
+ Three declarations follow from that, and the framework enforces each:
43
+
44
+ - **`clips = True`** — a signed step can push a pixel past the selection's value
45
+ range, so the output is clipped back rather than refused.
46
+ - **`reversible = False`** — the step is lossy. The original pixels are not
47
+ recoverable from the output, so the row records that it is not invertible.
48
+ - **Deterministic** — no randomness is drawn, so the recorded seed is `None`.
49
+ The same input and the same `epsilon` always give the same output.
50
+
51
+ `epsilon` is the adversarial budget, strictly positive, and sweepable, so a run
52
+ can walk a whole budget curve.
53
+
54
+ ## Labels do not move
55
+
56
+ An attack moves the model's *prediction*, not the truth. The ground-truth label
57
+ belongs to the source row, travels with it, and is never touched here — this
58
+ package has no notion of a label at all, only of pixels.
59
+
60
+ That is what makes an adversarial sample meaningful: if the label had moved
61
+ along with the pixels, the pair would prove nothing. A label that changed under
62
+ perturbation, or a target model whose response was ignored, would both mean the
63
+ measurement was not an attack at all.
64
+
65
+ ## Example
66
+
67
+ The `models` and `operations` sections of a job configuration, with a target
68
+ model supplied as your own source:
69
+
70
+ ```yaml
71
+ models:
72
+ yolo:
73
+ type: python
74
+ path: adapters/yolo_target.py
75
+ export: YoloTarget
76
+ weights: yolov8n.pt
77
+ params: { conf: 0.25 }
78
+ operations:
79
+ transformations:
80
+ - name: fgsm
81
+ type: fgsm
82
+ target_model: yolo
83
+ epsilon:
84
+ range: [0.01, 0.05]
85
+ step: 0.01
86
+ ```
87
+
88
+ The transformation names its model with `target_model: yolo`. Only `grad` is
89
+ used from it, and its output is checked for shape and finiteness before the step,
90
+ so a misbehaving adapter fails loudly rather than corrupting the batch.
91
+
92
+ A target model is recognised by a non-empty `name` plus a `grad` method, and
93
+ conformance is checked against the `target` role the transformation declares.
@@ -0,0 +1,41 @@
1
+ [project]
2
+ name = "kcai-data-sampling-fgsm"
3
+ dynamic = ["dependencies", "version"]
4
+ description = "Adversarial perturbation (FGSM) for kcai data-sampling"
5
+ authors = [
6
+ {name = "Safenai", email = "support@safenai.io"},
7
+ ]
8
+ license = "Apache-2.0"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ keywords = ["ml", "data", "augmentation", "robustness", "adversarial", "fgsm"]
12
+ classifiers = [
13
+ "Development Status :: 3 - Alpha",
14
+ "Intended Audience :: Developers",
15
+ "Topic :: Software Development :: Libraries :: Python Modules",
16
+ "Programming Language :: Python :: 3.11",
17
+ "Programming Language :: Python :: 3.12",
18
+ "Programming Language :: Python :: 3.13",
19
+ "Programming Language :: Python :: 3.14",
20
+ ]
21
+
22
+ [project.entry-points."kcai_data_sampling.transformations"]
23
+ fgsm = "kcai_data_sampling_fgsm.api.transformations.fgsm:Fgsm"
24
+
25
+ [build-system]
26
+ requires = ["setuptools>=80", "setuptools-scm[simple]>=8"]
27
+ build-backend = "setuptools.build_meta"
28
+
29
+ [tool.setuptools_scm]
30
+ version_file = "src/kcai_data_sampling_fgsm/_version_.py"
31
+ root = "../.."
32
+ fallback_version = "0.0.1"
33
+
34
+ [tool.setuptools.dynamic]
35
+ dependencies = {file = ["requirements.txt"]}
36
+
37
+ [tool.setuptools.packages.find]
38
+ where = ["src"]
39
+
40
+ [tool.setuptools.package-data]
41
+ kcai_data_sampling_fgsm = ["py.typed"]
@@ -0,0 +1 @@
1
+ kcai-data-sampling-core
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,12 @@
1
+ """Adversarial perturbation with the Fast Gradient Sign Method.
2
+
3
+ Ships the ``fgsm`` transformation (``model_role = "target"``): a budgeted
4
+ sign-direction step along the gradient of the user's target model, expressed in
5
+ normalized pixel units. The transformation class lives under
6
+ ``api/transformations/``, the pure step math under ``transformations/``, and
7
+ the configuration schema at the package root. No model framework is imported
8
+ and no model ships: the target model is the user's, provided at run time
9
+ through the ``models:`` section.
10
+ """
11
+
12
+ from kcai_data_sampling_fgsm._version_ import __version__ as __version__
@@ -0,0 +1,24 @@
1
+ # file generated by vcs-versioning
2
+ # don't change, don't track in version control
3
+ from __future__ import annotations
4
+
5
+ __all__ = [
6
+ "__version__",
7
+ "__version_tuple__",
8
+ "version",
9
+ "version_tuple",
10
+ "__commit_id__",
11
+ "commit_id",
12
+ ]
13
+
14
+ version: str
15
+ __version__: str
16
+ __version_tuple__: tuple[int | str, ...]
17
+ version_tuple: tuple[int | str, ...]
18
+ commit_id: str | None
19
+ __commit_id__: str | None
20
+
21
+ __version__ = version = '0.1.0'
22
+ __version_tuple__ = version_tuple = (0, 1, 0)
23
+
24
+ __commit_id__ = commit_id = None
@@ -0,0 +1,7 @@
1
+ """Subclasses of the generic core contracts.
2
+
3
+ The transformation classes wrap the pure step math from
4
+ ``kcai_data_sampling_fgsm.transformations`` into the unary ``apply`` contract.
5
+ I/O stays out: reads happen in the ``-job`` dataloaders and writes in the
6
+ ``-job`` outputwriters; everything flows as image batches.
7
+ """
@@ -0,0 +1,10 @@
1
+ """Unary transformation classes.
2
+
3
+ The generic core contract lives in ``kcai_data_sampling_core.api``; the
4
+ ``Fgsm`` class here wraps the pure step function from
5
+ ``kcai_data_sampling_fgsm.transformations`` into the unary ``apply`` contract.
6
+ """
7
+
8
+ from kcai_data_sampling_fgsm.api.transformations.fgsm import Fgsm
9
+
10
+ __all__ = ["Fgsm"]
@@ -0,0 +1,68 @@
1
+ """The ``fgsm`` transformation class.
2
+
3
+ Wraps the normalized sign-direction step
4
+ (:func:`kcai_data_sampling_fgsm.transformations.fgsm.fgsm_step`) into the
5
+ unary transformation contract. The target model — the user's — is queried on
6
+ the normalized float batch and its gradient is funneled through
7
+ ``check_output`` (shape and finiteness) before the step.
8
+ """
9
+
10
+ from kcai_data_sampling_core.api.roles import check_output
11
+ from kcai_data_sampling_core.api.unary import UnaryTransformation
12
+ import numpy as np
13
+ from typing_extensions import override
14
+
15
+ from kcai_data_sampling_fgsm.configs import FgsmTransformationConfig
16
+ from kcai_data_sampling_fgsm.transformations.fgsm import fgsm_step
17
+
18
+
19
+ class Fgsm(UnaryTransformation):
20
+ """One budgeted step along the sign of the target model's gradient, in L-infinity.
21
+
22
+ The ``epsilon``-signed step may push pixels past the selection's value
23
+ range, so the algorithm declares ``clips`` and the base clips the output
24
+ back to it. The step is a lossy perturbation (not ``reversible``) and
25
+ deterministic, so the row records no seed. The target model is the user's
26
+ ``TargetModel``: only its ``grad`` is used.
27
+ """
28
+
29
+ algorithm = "fgsm"
30
+
31
+ #: The registered config schema this algorithm validates against.
32
+ Config = FgsmTransformationConfig
33
+
34
+ model_role = "target"
35
+ model_methods = ("grad",)
36
+
37
+ clips = True
38
+ reversible = False
39
+
40
+ @override
41
+ def apply(
42
+ self,
43
+ xs: np.ndarray, # (b, h, w, c) uint8
44
+ rngs: list[np.random.Generator] | None = None,
45
+ ) -> np.ndarray:
46
+ """Perturb the batch by ``epsilon`` along the sign of the target gradient.
47
+
48
+ Args:
49
+ xs: Batch of sample arrays shaped ``(B, *sample)``.
50
+ rngs: Unused for this deterministic operation.
51
+
52
+ Returns:
53
+ A batch of the same shape and dtype, clipped within the value range.
54
+
55
+ Raises:
56
+ ValueError: If the target model's ``grad`` output breaks the
57
+ numeric contract (wrong shape or non-finite).
58
+ """
59
+ del rngs
60
+ normalized = xs.astype(np.float64) / np.iinfo(xs.dtype).max
61
+ grad = check_output(
62
+ self.algorithm,
63
+ self.target_model,
64
+ "grad",
65
+ normalized,
66
+ self.target_model.grad(normalized),
67
+ )
68
+ return fgsm_step(xs, grad, self.params["epsilon"])
@@ -0,0 +1,57 @@
1
+ """The ``fgsm`` transformation's configuration schema.
2
+
3
+ The schema subclasses the core base ``TransformationConfig`` and pins ``type``
4
+ to the algorithm's literal, so the registry-resolved validator in ``JobConfig``
5
+ picks it by type. ``epsilon`` — the adversarial budget — is required, in
6
+ normalized ``[0, 1]`` pixel units, strictly positive, and sweepable (its
7
+ interval must stay ``> 0``). ``target_model`` names a model from the
8
+ ``models:`` section of the job config; the CLI resolves the name to an
9
+ instance.
10
+ """
11
+
12
+ from typing import Literal, Self
13
+
14
+ from kcai_data_sampling_core.models.config import TransformationConfig
15
+ from kcai_data_sampling_core.models.sweep import SweepConfig
16
+ from pydantic import Field, model_validator
17
+
18
+
19
+ class FgsmTransformationConfig(TransformationConfig):
20
+ """Configuration of the ``fgsm`` transformation.
21
+
22
+ Attributes:
23
+ target_model: Name of a target model from the job's ``models:``
24
+ section; the CLI resolves it to an instance. Optional here because
25
+ the transformation base consumes it before re-validating the
26
+ remaining parameters against this schema; a model-role
27
+ transformation without one is refused loudly at construction (the
28
+ slot check).
29
+ epsilon: Adversarial budget in normalized ``[0, 1]`` pixel units,
30
+ strictly positive, or a ``SweepConfig`` expanding it (its interval
31
+ must stay ``> 0``).
32
+ """
33
+
34
+ type: Literal["fgsm"] = "fgsm"
35
+ target_model: str | None = Field(
36
+ default=None,
37
+ exclude=True,
38
+ description="Name of a target model from the job's models: section; excluded"
39
+ " from the resolved parameters (the base consumes it before validation).",
40
+ )
41
+ epsilon: float | SweepConfig = Field(
42
+ description="Adversarial budget in normalized [0, 1] pixel units; a SweepConfig expands it."
43
+ )
44
+
45
+ @model_validator(mode="after")
46
+ def _parameter_bounds(self) -> Self:
47
+ """Enforce the epsilon budget's range on the value or the sweep.
48
+
49
+ Returns:
50
+ The validated config.
51
+
52
+ Raises:
53
+ ValueError: If ``epsilon`` is not strictly positive, whether given
54
+ directly or as a sweep interval.
55
+ """
56
+ self._check_parameter_bounds("epsilon", minimum=0, exclusive_min=True)
57
+ return self
@@ -0,0 +1,11 @@
1
+ """Pure algorithm math for the adversarial transformations.
2
+
3
+ All transformations share the image-batch convention ``(B, H, W, 4) uint8``.
4
+ The module-level functions here are the pure algorithm math; the
5
+ transformation class that wraps them into the unary contract lives in
6
+ ``kcai_data_sampling_fgsm.api.transformations``.
7
+ """
8
+
9
+ from kcai_data_sampling_fgsm.transformations.fgsm import fgsm_step
10
+
11
+ __all__ = ["fgsm_step"]
@@ -0,0 +1,40 @@
1
+ """The FGSM step, in normalized units: the math.
2
+
3
+ ``fgsm_step(xs, grad, epsilon)`` is the pure numpy map — the transformation
4
+ class that wraps it into the unary contract lives in
5
+ ``kcai_data_sampling_fgsm.api.transformations.fgsm``. The step runs in
6
+ normalized ``[0, 1]`` pixel units (the batch divided by its dtype maximum), and
7
+ the model's gradient is in the same units: only its sign participates.
8
+ """
9
+
10
+ import numpy as np
11
+
12
+
13
+ def fgsm_step(xs: np.ndarray, grad: np.ndarray, epsilon: float) -> np.ndarray:
14
+ """Apply one budgeted sign-direction step in normalized ``[0, 1]`` units.
15
+
16
+ Normalizes the integer batch by its dtype maximum, adds
17
+ ``epsilon * sign(grad)``, clips back to ``[0, 1]``, and restores the
18
+ batch's dtype (scale, round, cast). ``grad`` is the target model's gradient
19
+ in the same normalized units — the step is ``epsilon * sign(grad)``, so
20
+ only the sign matters.
21
+
22
+ Args:
23
+ xs: Integer batch of sample arrays ``(B, *sample)``.
24
+ grad: Signed gradient in normalized units, same shape as ``xs``.
25
+ epsilon: Adversarial budget in normalized ``[0, 1]`` pixel units,
26
+ strictly positive.
27
+
28
+ Returns:
29
+ The perturbed batch, same shape and dtype as ``xs``.
30
+
31
+ Raises:
32
+ ValueError: If ``xs`` is not an integer array (a normalization-by-max
33
+ has no meaning otherwise).
34
+ """
35
+ if not np.issubdtype(xs.dtype, np.integer):
36
+ raise ValueError(f"fgsm_step: integer batches only, got dtype {xs.dtype}")
37
+ info = np.iinfo(xs.dtype)
38
+ normalized = xs.astype(np.float64) / info.max
39
+ stepped = np.clip(normalized + epsilon * np.sign(grad), 0.0, 1.0)
40
+ return np.rint(stepped * info.max).astype(xs.dtype)
@@ -0,0 +1,111 @@
1
+ Metadata-Version: 2.4
2
+ Name: kcai-data-sampling-fgsm
3
+ Version: 0.1.0
4
+ Summary: Adversarial perturbation (FGSM) for kcai data-sampling
5
+ Author-email: Safenai <support@safenai.io>
6
+ License-Expression: Apache-2.0
7
+ Keywords: ml,data,augmentation,robustness,adversarial,fgsm
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
15
+ Requires-Python: >=3.11
16
+ Description-Content-Type: text/markdown
17
+ Requires-Dist: kcai-data-sampling-core
18
+
19
+ # kcai-data-sampling-fgsm
20
+
21
+ The **adversarial** slot of kcai data-sampling: transformations where a model's
22
+ *response* enters the computation and the result is graded against it. Here the
23
+ model is a **target** — it is not asked to produce anything, only to react. That
24
+ is what makes the family adversarial, and the declaring `model_role = "target"`
25
+ is what tells the framework to treat it as such.
26
+
27
+ This package implements the Fast Gradient Sign Method as a single budgeted step
28
+ along the sign of the target model's gradient, and exposes it through the
29
+ `kcai_data_sampling.transformations` entry-point group.
30
+
31
+ **The target model is yours.** It arrives at run time through the `models:`
32
+ section of your configuration and is never shipped by this package.
33
+
34
+ ## What it ships today
35
+
36
+ - `fgsm` — one method: one L-infinity step of budget `epsilon` along the sign of
37
+ the target's gradient.
38
+
39
+ One method, as an example of the slot rather than a catalogue.
40
+
41
+ ## Install
42
+
43
+ ```bash
44
+ pip install "kcai-data-sampling[fgsm]"
45
+ ```
46
+
47
+ **No deep-learning framework is required.** This package depends only on the
48
+ core contracts — the gradient arrives from *your* model, so the work is yours
49
+ too, and nothing here pulls torch. A configuration driving `fgsm` may well need
50
+ torch in the environment that hosts the target model; that is a property of the
51
+ model you bring, not of this package.
52
+
53
+ ## How the step works
54
+
55
+ The batch is normalized to `[0, 1]` pixel units, the target's gradient is taken
56
+ in the same units, and `epsilon * sign(grad)` is added — so only the *sign* of
57
+ the gradient participates, not its magnitude. The result is clipped back into
58
+ range and restored to the batch's dtype.
59
+
60
+ Three declarations follow from that, and the framework enforces each:
61
+
62
+ - **`clips = True`** — a signed step can push a pixel past the selection's value
63
+ range, so the output is clipped back rather than refused.
64
+ - **`reversible = False`** — the step is lossy. The original pixels are not
65
+ recoverable from the output, so the row records that it is not invertible.
66
+ - **Deterministic** — no randomness is drawn, so the recorded seed is `None`.
67
+ The same input and the same `epsilon` always give the same output.
68
+
69
+ `epsilon` is the adversarial budget, strictly positive, and sweepable, so a run
70
+ can walk a whole budget curve.
71
+
72
+ ## Labels do not move
73
+
74
+ An attack moves the model's *prediction*, not the truth. The ground-truth label
75
+ belongs to the source row, travels with it, and is never touched here — this
76
+ package has no notion of a label at all, only of pixels.
77
+
78
+ That is what makes an adversarial sample meaningful: if the label had moved
79
+ along with the pixels, the pair would prove nothing. A label that changed under
80
+ perturbation, or a target model whose response was ignored, would both mean the
81
+ measurement was not an attack at all.
82
+
83
+ ## Example
84
+
85
+ The `models` and `operations` sections of a job configuration, with a target
86
+ model supplied as your own source:
87
+
88
+ ```yaml
89
+ models:
90
+ yolo:
91
+ type: python
92
+ path: adapters/yolo_target.py
93
+ export: YoloTarget
94
+ weights: yolov8n.pt
95
+ params: { conf: 0.25 }
96
+ operations:
97
+ transformations:
98
+ - name: fgsm
99
+ type: fgsm
100
+ target_model: yolo
101
+ epsilon:
102
+ range: [0.01, 0.05]
103
+ step: 0.01
104
+ ```
105
+
106
+ The transformation names its model with `target_model: yolo`. Only `grad` is
107
+ used from it, and its output is checked for shape and finiteness before the step,
108
+ so a misbehaving adapter fails loudly rather than corrupting the batch.
109
+
110
+ A target model is recognised by a non-empty `name` plus a `grad` method, and
111
+ conformance is checked against the `target` role the transformation declares.
@@ -0,0 +1,19 @@
1
+ README.md
2
+ pyproject.toml
3
+ requirements.txt
4
+ src/kcai_data_sampling_fgsm/__init__.py
5
+ src/kcai_data_sampling_fgsm/_version_.py
6
+ src/kcai_data_sampling_fgsm/configs.py
7
+ src/kcai_data_sampling_fgsm/py.typed
8
+ src/kcai_data_sampling_fgsm.egg-info/PKG-INFO
9
+ src/kcai_data_sampling_fgsm.egg-info/SOURCES.txt
10
+ src/kcai_data_sampling_fgsm.egg-info/dependency_links.txt
11
+ src/kcai_data_sampling_fgsm.egg-info/entry_points.txt
12
+ src/kcai_data_sampling_fgsm.egg-info/requires.txt
13
+ src/kcai_data_sampling_fgsm.egg-info/scm_file_list.json
14
+ src/kcai_data_sampling_fgsm.egg-info/top_level.txt
15
+ src/kcai_data_sampling_fgsm/api/__init__.py
16
+ src/kcai_data_sampling_fgsm/api/transformations/__init__.py
17
+ src/kcai_data_sampling_fgsm/api/transformations/fgsm.py
18
+ src/kcai_data_sampling_fgsm/transformations/__init__.py
19
+ src/kcai_data_sampling_fgsm/transformations/fgsm.py
@@ -0,0 +1,2 @@
1
+ [kcai_data_sampling.transformations]
2
+ fgsm = kcai_data_sampling_fgsm.api.transformations.fgsm:Fgsm
@@ -0,0 +1,15 @@
1
+ {
2
+ "files": [
3
+ "README.md",
4
+ "pyproject.toml",
5
+ "requirements.txt",
6
+ "src/kcai_data_sampling_fgsm/__init__.py",
7
+ "src/kcai_data_sampling_fgsm/api/__init__.py",
8
+ "src/kcai_data_sampling_fgsm/api/transformations/__init__.py",
9
+ "src/kcai_data_sampling_fgsm/api/transformations/fgsm.py",
10
+ "src/kcai_data_sampling_fgsm/configs.py",
11
+ "src/kcai_data_sampling_fgsm/py.typed",
12
+ "src/kcai_data_sampling_fgsm/transformations/__init__.py",
13
+ "src/kcai_data_sampling_fgsm/transformations/fgsm.py"
14
+ ]
15
+ }