Skip to content

configuration_model

Pydantic CAREamics configuration.

Configuration #

Bases: BaseModel

CAREamics configuration.

The configuration defines all parameters used to build and train a CAREamics model. These parameters are validated to ensure that they are compatible with each other.

It contains three sub-configurations:

  • AlgorithmModel: configuration for the algorithm training, which includes the architecture, loss function, optimizer, and other hyperparameters.
  • DataModel: configuration for the dataloader, which includes the type of data, transformations, mean/std and other parameters.
  • TrainingModel: configuration for the training, which includes the number of epochs or the callbacks.

Attributes:

Name Type Description
experiment_name str

Name of the experiment, used when saving logs and checkpoints.

algorithm AlgorithmModel

Algorithm configuration.

data DataModel

Data configuration.

training TrainingModel

Training configuration.

Methods:

Name Description
set_3D

Switch configuration between 2D and 3D.

set_N2V2

Switch N2V algorithm between N2V and N2V2.

set_structN2V

mask_axis: Literal["horizontal", "vertical", "none"], mask_span: int) -> None Set StructN2V parameters.

model_dump

exclude_defaults: bool = False, exclude_none: bool = True, **kwargs: Dict ) -> Dict Export configuration to a dictionary.

Raises:

Type Description
ValueError

Configuration parameter type validation errors.

ValueError

If the experiment name contains invalid characters or is empty.

ValueError

If the algorithm is 3D but there is not "Z" in the data axes, or 2D algorithm with "Z" in data axes.

ValueError

Algorithm, data or training validation errors.

Notes

We provide convenience methods to create standards configurations, for instance for N2V, in the careamics.config.configuration_factory module.

from careamics.config.configuration_factory import create_n2v_configuration config = create_n2v_configuration( ... experiment_name="n2v_experiment", ... data_type="array", ... axes="YX", ... patch_size=[64, 64], ... batch_size=32, ... num_epochs=100 ... )

The configuration can be exported to a dictionary using the model_dump method:

config_dict = config.model_dump()

Configurations can also be exported or imported from yaml files:

from careamics.config import save_configuration, load_configuration path_to_config = save_configuration(config, my_path / "config.yml") other_config = load_configuration(path_to_config)

Examples:

Minimum example:

>>> from careamics.config import Configuration
>>> config_dict = {
...         "experiment_name": "N2V_experiment",
...         "algorithm_config": {
...             "algorithm": "n2v",
...             "loss": "n2v",
...             "model": {
...                 "architecture": "UNet",
...             },
...         },
...         "training_config": {
...             "num_epochs": 200,
...         },
...         "data_config": {
...             "data_type": "tiff",
...             "patch_size": [64, 64],
...             "axes": "SYX",
...         },
...     }
>>> config = Configuration(**config_dict)
Source code in src/careamics/config/configuration_model.py
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
class Configuration(BaseModel):
    """
    CAREamics configuration.

    The configuration defines all parameters used to build and train a CAREamics model.
    These parameters are validated to ensure that they are compatible with each other.

    It contains three sub-configurations:

    - AlgorithmModel: configuration for the algorithm training, which includes the
        architecture, loss function, optimizer, and other hyperparameters.
    - DataModel: configuration for the dataloader, which includes the type of data,
        transformations, mean/std and other parameters.
    - TrainingModel: configuration for the training, which includes the number of
        epochs or the callbacks.

    Attributes
    ----------
    experiment_name : str
        Name of the experiment, used when saving logs and checkpoints.
    algorithm : AlgorithmModel
        Algorithm configuration.
    data : DataModel
        Data configuration.
    training : TrainingModel
        Training configuration.

    Methods
    -------
    set_3D(is_3D: bool, axes: str, patch_size: List[int]) -> None
        Switch configuration between 2D and 3D.
    set_N2V2(use_n2v2: bool) -> None
        Switch N2V algorithm between N2V and N2V2.
    set_structN2V(
        mask_axis: Literal["horizontal", "vertical", "none"], mask_span: int) -> None
        Set StructN2V parameters.
    model_dump(
        exclude_defaults: bool = False, exclude_none: bool = True, **kwargs: Dict
        ) -> Dict
        Export configuration to a dictionary.

    Raises
    ------
    ValueError
        Configuration parameter type validation errors.
    ValueError
        If the experiment name contains invalid characters or is empty.
    ValueError
        If the algorithm is 3D but there is not "Z" in the data axes, or 2D algorithm
        with "Z" in data axes.
    ValueError
        Algorithm, data or training validation errors.

    Notes
    -----
    We provide convenience methods to create standards configurations, for instance
    for N2V, in the `careamics.config.configuration_factory` module.
    >>> from careamics.config.configuration_factory import create_n2v_configuration
    >>> config = create_n2v_configuration(
    ...     experiment_name="n2v_experiment",
    ...     data_type="array",
    ...     axes="YX",
    ...     patch_size=[64, 64],
    ...     batch_size=32,
    ...     num_epochs=100
    ... )

    The configuration can be exported to a dictionary using the model_dump method:
    >>> config_dict = config.model_dump()

    Configurations can also be exported or imported from yaml files:
    >>> from careamics.config import save_configuration, load_configuration
    >>> path_to_config = save_configuration(config, my_path / "config.yml")
    >>> other_config = load_configuration(path_to_config)

    Examples
    --------
    Minimum example:
    >>> from careamics.config import Configuration
    >>> config_dict = {
    ...         "experiment_name": "N2V_experiment",
    ...         "algorithm_config": {
    ...             "algorithm": "n2v",
    ...             "loss": "n2v",
    ...             "model": {
    ...                 "architecture": "UNet",
    ...             },
    ...         },
    ...         "training_config": {
    ...             "num_epochs": 200,
    ...         },
    ...         "data_config": {
    ...             "data_type": "tiff",
    ...             "patch_size": [64, 64],
    ...             "axes": "SYX",
    ...         },
    ...     }
    >>> config = Configuration(**config_dict)
    """

    model_config = ConfigDict(
        validate_assignment=True,
        set_arbitrary_types_allowed=True,
    )

    # version
    version: Literal["0.1.0"] = "0.1.0"
    """CAREamics configuration version."""

    # required parameters
    experiment_name: str
    """Name of the experiment, used to name logs and checkpoints."""

    # Sub-configurations
    algorithm_config: Union[FCNAlgorithmConfig, VAEAlgorithmConfig] = Field(
        discriminator="algorithm"
    )
    """Algorithm configuration, holding all parameters required to configure the
    model."""

    data_config: DataConfig
    """Data configuration, holding all parameters required to configure the training
    data loader."""

    training_config: TrainingConfig
    """Training configuration, holding all parameters required to configure the
    training process."""

    @field_validator("experiment_name")
    @classmethod
    def no_symbol(cls, name: str) -> str:
        """
        Validate experiment name.

        A valid experiment name is a non-empty string with only contains letters,
        numbers, underscores, dashes and spaces.

        Parameters
        ----------
        name : str
            Name to validate.

        Returns
        -------
        str
            Validated name.

        Raises
        ------
        ValueError
            If the name is empty or contains invalid characters.
        """
        if len(name) == 0 or name.isspace():
            raise ValueError("Experiment name is empty.")

        # Validate using a regex that it contains only letters, numbers, underscores,
        # dashes and spaces
        if not re.match(r"^[a-zA-Z0-9_\- ]*$", name):
            raise ValueError(
                f"Experiment name contains invalid characters (got {name}). "
                f"Only letters, numbers, underscores, dashes and spaces are allowed."
            )

        return name

    @model_validator(mode="after")
    def validate_3D(self: Self) -> Self:
        """
        Change algorithm dimensions to match data.axes.

        Only for non-custom algorithms.

        Returns
        -------
        Self
            Validated configuration.
        """
        if self.algorithm_config.algorithm != SupportedAlgorithm.CUSTOM:
            if "Z" in self.data_config.axes and not self.algorithm_config.model.is_3D():
                # change algorithm to 3D
                self.algorithm_config.model.set_3D(True)
            elif (
                "Z" not in self.data_config.axes and self.algorithm_config.model.is_3D()
            ):
                # change algorithm to 2D
                self.algorithm_config.model.set_3D(False)

        return self

    @model_validator(mode="after")
    def validate_algorithm_and_data(self: Self) -> Self:
        """
        Validate algorithm and data compatibility.

        In particular, the validation does the following:

        - If N2V is used, it enforces the presence of N2V_Maniuplate in the transforms
        - If N2V2 is used, it enforces the correct manipulation strategy

        Returns
        -------
        Self
            Validated configuration.
        """
        if self.algorithm_config.algorithm == SupportedAlgorithm.N2V:
            # missing N2V_MANIPULATE
            if not self.data_config.has_n2v_manipulate():
                self.data_config.transforms.append(
                    N2VManipulateModel(
                        name=SupportedTransform.N2V_MANIPULATE.value,
                    )
                )

            median = SupportedPixelManipulation.MEDIAN.value
            uniform = SupportedPixelManipulation.UNIFORM.value
            strategy = median if self.algorithm_config.model.n2v2 else uniform
            self.data_config.set_N2V2_strategy(strategy)
        else:
            # remove N2V manipulate if present
            if self.data_config.has_n2v_manipulate():
                self.data_config.remove_n2v_manipulate()

        return self

    def __str__(self) -> str:
        """
        Pretty string reprensenting the configuration.

        Returns
        -------
        str
            Pretty string.
        """
        return pformat(self.model_dump())

    def set_3D(self, is_3D: bool, axes: str, patch_size: list[int]) -> None:
        """
        Set 3D flag and axes.

        Parameters
        ----------
        is_3D : bool
            Whether the algorithm is 3D or not.
        axes : str
            Axes of the data.
        patch_size : list[int]
            Patch size.
        """
        # set the flag and axes (this will not trigger validation at the config level)
        self.algorithm_config.model.set_3D(is_3D)
        self.data_config.set_3D(axes, patch_size)

        # cheap hack: trigger validation
        self.algorithm_config = self.algorithm_config

    def set_N2V2(self, use_n2v2: bool) -> None:
        """
        Switch N2V algorithm between N2V and N2V2.

        Parameters
        ----------
        use_n2v2 : bool
            Whether to use N2V2 or not.

        Raises
        ------
        ValueError
            If the algorithm is not N2V.
        """
        if self.algorithm_config.algorithm == SupportedAlgorithm.N2V:
            self.algorithm_config.model.n2v2 = use_n2v2
            strategy = (
                SupportedPixelManipulation.MEDIAN.value
                if use_n2v2
                else SupportedPixelManipulation.UNIFORM.value
            )
            self.data_config.set_N2V2_strategy(strategy)
        else:
            raise ValueError("N2V2 can only be set for N2V algorithm.")

    def set_structN2V(
        self, mask_axis: Literal["horizontal", "vertical", "none"], mask_span: int
    ) -> None:
        """
        Set StructN2V parameters.

        Parameters
        ----------
        mask_axis : Literal["horizontal", "vertical", "none"]
            Axis of the structural mask.
        mask_span : int
            Span of the structural mask.
        """
        self.data_config.set_structN2V_mask(mask_axis, mask_span)

    def get_algorithm_flavour(self) -> str:
        """
        Get the algorithm name.

        Returns
        -------
        str
            Algorithm name.
        """
        if self.algorithm_config.algorithm == SupportedAlgorithm.N2V:
            use_n2v2 = self.algorithm_config.model.n2v2
            use_structN2V = self.data_config.transforms[-1].struct_mask_axis != "none"

            # return the n2v flavour
            if use_n2v2 and use_structN2V:
                return STRUCT_N2V2
            elif use_n2v2:
                return N2V2
            elif use_structN2V:
                return STRUCT_N2V
            else:
                return N2V
        elif self.algorithm_config.algorithm == SupportedAlgorithm.N2N:
            return N2N
        elif self.algorithm_config.algorithm == SupportedAlgorithm.CARE:
            return CARE
        else:
            return CUSTOM

    def get_algorithm_description(self) -> str:
        """
        Return a description of the algorithm.

        This method is used to generate the README of the BioImage Model Zoo export.

        Returns
        -------
        str
            Description of the algorithm.
        """
        algorithm_flavour = self.get_algorithm_flavour()

        if algorithm_flavour == CUSTOM:
            return f"Custom algorithm, named {self.algorithm_config.model.name}"
        else:  # currently only N2V flavours
            if algorithm_flavour == N2V:
                return N2VDescription().description
            elif algorithm_flavour == N2V2:
                return N2V2Description().description
            elif algorithm_flavour == STRUCT_N2V:
                return StructN2VDescription().description
            elif algorithm_flavour == STRUCT_N2V2:
                return StructN2V2Description().description
            elif algorithm_flavour == N2N:
                return N2NDescription().description
            elif algorithm_flavour == CARE:
                return CAREDescription().description

        return ""

    def get_algorithm_citations(self) -> list[CiteEntry]:
        """
        Return a list of citation entries of the current algorithm.

        This is used to generate the model description for the BioImage Model Zoo.

        Returns
        -------
        List[CiteEntry]
            List of citation entries.
        """
        if self.algorithm_config.algorithm == SupportedAlgorithm.N2V:
            use_n2v2 = self.algorithm_config.model.n2v2
            use_structN2V = self.data_config.transforms[-1].struct_mask_axis != "none"

            # return the (struct)N2V(2) references
            if use_n2v2 and use_structN2V:
                return [N2VRef, N2V2Ref, StructN2VRef]
            elif use_n2v2:
                return [N2VRef, N2V2Ref]
            elif use_structN2V:
                return [N2VRef, StructN2VRef]
            else:
                return [N2VRef]
        elif self.algorithm_config.algorithm == SupportedAlgorithm.N2N:
            return [N2NRef]
        elif self.algorithm_config.algorithm == SupportedAlgorithm.CARE:
            return [CARERef]

        raise ValueError("Citation not available for custom algorithm.")

    def get_algorithm_references(self) -> str:
        """
        Get the algorithm references.

        This is used to generate the README of the BioImage Model Zoo export.

        Returns
        -------
        str
            Algorithm references.
        """
        if self.algorithm_config.algorithm == SupportedAlgorithm.N2V:
            use_n2v2 = self.algorithm_config.model.n2v2
            use_structN2V = self.data_config.transforms[-1].struct_mask_axis != "none"

            references = [
                N2VRef.text + " doi: " + N2VRef.doi,
                N2V2Ref.text + " doi: " + N2V2Ref.doi,
                StructN2VRef.text + " doi: " + StructN2VRef.doi,
            ]

            # return the (struct)N2V(2) references
            if use_n2v2 and use_structN2V:
                return "".join(references)
            elif use_n2v2:
                references.pop(-1)
                return "".join(references)
            elif use_structN2V:
                references.pop(-2)
                return "".join(references)
            else:
                return references[0]

        return ""

    def get_algorithm_keywords(self) -> list[str]:
        """
        Get algorithm keywords.

        Returns
        -------
        list[str]
            List of keywords.
        """
        if self.algorithm_config.algorithm == SupportedAlgorithm.N2V:
            use_n2v2 = self.algorithm_config.model.n2v2
            use_structN2V = self.data_config.transforms[-1].struct_mask_axis != "none"

            keywords = [
                "denoising",
                "restoration",
                "UNet",
                "3D" if "Z" in self.data_config.axes else "2D",
                "CAREamics",
                "pytorch",
                N2V,
            ]

            if use_n2v2:
                keywords.append(N2V2)
            if use_structN2V:
                keywords.append(STRUCT_N2V)
        else:
            keywords = ["CAREamics"]

        return keywords

    def model_dump(
        self,
        exclude_defaults: bool = False,
        exclude_none: bool = True,
        **kwargs: dict,
    ) -> dict:
        """
        Override model_dump method in order to set default values.

        Parameters
        ----------
        exclude_defaults : bool, optional
            Whether to exclude fields with default values or not, by default
            True.
        exclude_none : bool, optional
            Whether to exclude fields with None values or not, by default True.
        **kwargs : dict
            Keyword arguments.

        Returns
        -------
        dict
            Dictionary containing the model parameters.
        """
        dictionary = super().model_dump(
            exclude_none=exclude_none, exclude_defaults=exclude_defaults, **kwargs
        )

        return dictionary

algorithm_config: Union[FCNAlgorithmConfig, VAEAlgorithmConfig] = Field(discriminator='algorithm') class-attribute instance-attribute #

Algorithm configuration, holding all parameters required to configure the model.

data_config: DataConfig instance-attribute #

Data configuration, holding all parameters required to configure the training data loader.

experiment_name: str instance-attribute #

Name of the experiment, used to name logs and checkpoints.

training_config: TrainingConfig instance-attribute #

Training configuration, holding all parameters required to configure the training process.

version: Literal['0.1.0'] = '0.1.0' class-attribute instance-attribute #

CAREamics configuration version.

__str__() #

Pretty string reprensenting the configuration.

Returns:

Type Description
str

Pretty string.

Source code in src/careamics/config/configuration_model.py
def __str__(self) -> str:
    """
    Pretty string reprensenting the configuration.

    Returns
    -------
    str
        Pretty string.
    """
    return pformat(self.model_dump())

get_algorithm_citations() #

Return a list of citation entries of the current algorithm.

This is used to generate the model description for the BioImage Model Zoo.

Returns:

Type Description
List[CiteEntry]

List of citation entries.

Source code in src/careamics/config/configuration_model.py
def get_algorithm_citations(self) -> list[CiteEntry]:
    """
    Return a list of citation entries of the current algorithm.

    This is used to generate the model description for the BioImage Model Zoo.

    Returns
    -------
    List[CiteEntry]
        List of citation entries.
    """
    if self.algorithm_config.algorithm == SupportedAlgorithm.N2V:
        use_n2v2 = self.algorithm_config.model.n2v2
        use_structN2V = self.data_config.transforms[-1].struct_mask_axis != "none"

        # return the (struct)N2V(2) references
        if use_n2v2 and use_structN2V:
            return [N2VRef, N2V2Ref, StructN2VRef]
        elif use_n2v2:
            return [N2VRef, N2V2Ref]
        elif use_structN2V:
            return [N2VRef, StructN2VRef]
        else:
            return [N2VRef]
    elif self.algorithm_config.algorithm == SupportedAlgorithm.N2N:
        return [N2NRef]
    elif self.algorithm_config.algorithm == SupportedAlgorithm.CARE:
        return [CARERef]

    raise ValueError("Citation not available for custom algorithm.")

get_algorithm_description() #

Return a description of the algorithm.

This method is used to generate the README of the BioImage Model Zoo export.

Returns:

Type Description
str

Description of the algorithm.

Source code in src/careamics/config/configuration_model.py
def get_algorithm_description(self) -> str:
    """
    Return a description of the algorithm.

    This method is used to generate the README of the BioImage Model Zoo export.

    Returns
    -------
    str
        Description of the algorithm.
    """
    algorithm_flavour = self.get_algorithm_flavour()

    if algorithm_flavour == CUSTOM:
        return f"Custom algorithm, named {self.algorithm_config.model.name}"
    else:  # currently only N2V flavours
        if algorithm_flavour == N2V:
            return N2VDescription().description
        elif algorithm_flavour == N2V2:
            return N2V2Description().description
        elif algorithm_flavour == STRUCT_N2V:
            return StructN2VDescription().description
        elif algorithm_flavour == STRUCT_N2V2:
            return StructN2V2Description().description
        elif algorithm_flavour == N2N:
            return N2NDescription().description
        elif algorithm_flavour == CARE:
            return CAREDescription().description

    return ""

get_algorithm_flavour() #

Get the algorithm name.

Returns:

Type Description
str

Algorithm name.

Source code in src/careamics/config/configuration_model.py
def get_algorithm_flavour(self) -> str:
    """
    Get the algorithm name.

    Returns
    -------
    str
        Algorithm name.
    """
    if self.algorithm_config.algorithm == SupportedAlgorithm.N2V:
        use_n2v2 = self.algorithm_config.model.n2v2
        use_structN2V = self.data_config.transforms[-1].struct_mask_axis != "none"

        # return the n2v flavour
        if use_n2v2 and use_structN2V:
            return STRUCT_N2V2
        elif use_n2v2:
            return N2V2
        elif use_structN2V:
            return STRUCT_N2V
        else:
            return N2V
    elif self.algorithm_config.algorithm == SupportedAlgorithm.N2N:
        return N2N
    elif self.algorithm_config.algorithm == SupportedAlgorithm.CARE:
        return CARE
    else:
        return CUSTOM

get_algorithm_keywords() #

Get algorithm keywords.

Returns:

Type Description
list[str]

List of keywords.

Source code in src/careamics/config/configuration_model.py
def get_algorithm_keywords(self) -> list[str]:
    """
    Get algorithm keywords.

    Returns
    -------
    list[str]
        List of keywords.
    """
    if self.algorithm_config.algorithm == SupportedAlgorithm.N2V:
        use_n2v2 = self.algorithm_config.model.n2v2
        use_structN2V = self.data_config.transforms[-1].struct_mask_axis != "none"

        keywords = [
            "denoising",
            "restoration",
            "UNet",
            "3D" if "Z" in self.data_config.axes else "2D",
            "CAREamics",
            "pytorch",
            N2V,
        ]

        if use_n2v2:
            keywords.append(N2V2)
        if use_structN2V:
            keywords.append(STRUCT_N2V)
    else:
        keywords = ["CAREamics"]

    return keywords

get_algorithm_references() #

Get the algorithm references.

This is used to generate the README of the BioImage Model Zoo export.

Returns:

Type Description
str

Algorithm references.

Source code in src/careamics/config/configuration_model.py
def get_algorithm_references(self) -> str:
    """
    Get the algorithm references.

    This is used to generate the README of the BioImage Model Zoo export.

    Returns
    -------
    str
        Algorithm references.
    """
    if self.algorithm_config.algorithm == SupportedAlgorithm.N2V:
        use_n2v2 = self.algorithm_config.model.n2v2
        use_structN2V = self.data_config.transforms[-1].struct_mask_axis != "none"

        references = [
            N2VRef.text + " doi: " + N2VRef.doi,
            N2V2Ref.text + " doi: " + N2V2Ref.doi,
            StructN2VRef.text + " doi: " + StructN2VRef.doi,
        ]

        # return the (struct)N2V(2) references
        if use_n2v2 and use_structN2V:
            return "".join(references)
        elif use_n2v2:
            references.pop(-1)
            return "".join(references)
        elif use_structN2V:
            references.pop(-2)
            return "".join(references)
        else:
            return references[0]

    return ""

model_dump(exclude_defaults=False, exclude_none=True, **kwargs) #

Override model_dump method in order to set default values.

Parameters:

Name Type Description Default
exclude_defaults bool

Whether to exclude fields with default values or not, by default True.

False
exclude_none bool

Whether to exclude fields with None values or not, by default True.

True
**kwargs dict

Keyword arguments.

{}

Returns:

Type Description
dict

Dictionary containing the model parameters.

Source code in src/careamics/config/configuration_model.py
def model_dump(
    self,
    exclude_defaults: bool = False,
    exclude_none: bool = True,
    **kwargs: dict,
) -> dict:
    """
    Override model_dump method in order to set default values.

    Parameters
    ----------
    exclude_defaults : bool, optional
        Whether to exclude fields with default values or not, by default
        True.
    exclude_none : bool, optional
        Whether to exclude fields with None values or not, by default True.
    **kwargs : dict
        Keyword arguments.

    Returns
    -------
    dict
        Dictionary containing the model parameters.
    """
    dictionary = super().model_dump(
        exclude_none=exclude_none, exclude_defaults=exclude_defaults, **kwargs
    )

    return dictionary

no_symbol(name) classmethod #

Validate experiment name.

A valid experiment name is a non-empty string with only contains letters, numbers, underscores, dashes and spaces.

Parameters:

Name Type Description Default
name str

Name to validate.

required

Returns:

Type Description
str

Validated name.

Raises:

Type Description
ValueError

If the name is empty or contains invalid characters.

Source code in src/careamics/config/configuration_model.py
@field_validator("experiment_name")
@classmethod
def no_symbol(cls, name: str) -> str:
    """
    Validate experiment name.

    A valid experiment name is a non-empty string with only contains letters,
    numbers, underscores, dashes and spaces.

    Parameters
    ----------
    name : str
        Name to validate.

    Returns
    -------
    str
        Validated name.

    Raises
    ------
    ValueError
        If the name is empty or contains invalid characters.
    """
    if len(name) == 0 or name.isspace():
        raise ValueError("Experiment name is empty.")

    # Validate using a regex that it contains only letters, numbers, underscores,
    # dashes and spaces
    if not re.match(r"^[a-zA-Z0-9_\- ]*$", name):
        raise ValueError(
            f"Experiment name contains invalid characters (got {name}). "
            f"Only letters, numbers, underscores, dashes and spaces are allowed."
        )

    return name

set_3D(is_3D, axes, patch_size) #

Set 3D flag and axes.

Parameters:

Name Type Description Default
is_3D bool

Whether the algorithm is 3D or not.

required
axes str

Axes of the data.

required
patch_size list[int]

Patch size.

required
Source code in src/careamics/config/configuration_model.py
def set_3D(self, is_3D: bool, axes: str, patch_size: list[int]) -> None:
    """
    Set 3D flag and axes.

    Parameters
    ----------
    is_3D : bool
        Whether the algorithm is 3D or not.
    axes : str
        Axes of the data.
    patch_size : list[int]
        Patch size.
    """
    # set the flag and axes (this will not trigger validation at the config level)
    self.algorithm_config.model.set_3D(is_3D)
    self.data_config.set_3D(axes, patch_size)

    # cheap hack: trigger validation
    self.algorithm_config = self.algorithm_config

set_N2V2(use_n2v2) #

Switch N2V algorithm between N2V and N2V2.

Parameters:

Name Type Description Default
use_n2v2 bool

Whether to use N2V2 or not.

required

Raises:

Type Description
ValueError

If the algorithm is not N2V.

Source code in src/careamics/config/configuration_model.py
def set_N2V2(self, use_n2v2: bool) -> None:
    """
    Switch N2V algorithm between N2V and N2V2.

    Parameters
    ----------
    use_n2v2 : bool
        Whether to use N2V2 or not.

    Raises
    ------
    ValueError
        If the algorithm is not N2V.
    """
    if self.algorithm_config.algorithm == SupportedAlgorithm.N2V:
        self.algorithm_config.model.n2v2 = use_n2v2
        strategy = (
            SupportedPixelManipulation.MEDIAN.value
            if use_n2v2
            else SupportedPixelManipulation.UNIFORM.value
        )
        self.data_config.set_N2V2_strategy(strategy)
    else:
        raise ValueError("N2V2 can only be set for N2V algorithm.")

set_structN2V(mask_axis, mask_span) #

Set StructN2V parameters.

Parameters:

Name Type Description Default
mask_axis Literal['horizontal', 'vertical', 'none']

Axis of the structural mask.

required
mask_span int

Span of the structural mask.

required
Source code in src/careamics/config/configuration_model.py
def set_structN2V(
    self, mask_axis: Literal["horizontal", "vertical", "none"], mask_span: int
) -> None:
    """
    Set StructN2V parameters.

    Parameters
    ----------
    mask_axis : Literal["horizontal", "vertical", "none"]
        Axis of the structural mask.
    mask_span : int
        Span of the structural mask.
    """
    self.data_config.set_structN2V_mask(mask_axis, mask_span)

validate_3D() #

Change algorithm dimensions to match data.axes.

Only for non-custom algorithms.

Returns:

Type Description
Self

Validated configuration.

Source code in src/careamics/config/configuration_model.py
@model_validator(mode="after")
def validate_3D(self: Self) -> Self:
    """
    Change algorithm dimensions to match data.axes.

    Only for non-custom algorithms.

    Returns
    -------
    Self
        Validated configuration.
    """
    if self.algorithm_config.algorithm != SupportedAlgorithm.CUSTOM:
        if "Z" in self.data_config.axes and not self.algorithm_config.model.is_3D():
            # change algorithm to 3D
            self.algorithm_config.model.set_3D(True)
        elif (
            "Z" not in self.data_config.axes and self.algorithm_config.model.is_3D()
        ):
            # change algorithm to 2D
            self.algorithm_config.model.set_3D(False)

    return self

validate_algorithm_and_data() #

Validate algorithm and data compatibility.

In particular, the validation does the following:

  • If N2V is used, it enforces the presence of N2V_Maniuplate in the transforms
  • If N2V2 is used, it enforces the correct manipulation strategy

Returns:

Type Description
Self

Validated configuration.

Source code in src/careamics/config/configuration_model.py
@model_validator(mode="after")
def validate_algorithm_and_data(self: Self) -> Self:
    """
    Validate algorithm and data compatibility.

    In particular, the validation does the following:

    - If N2V is used, it enforces the presence of N2V_Maniuplate in the transforms
    - If N2V2 is used, it enforces the correct manipulation strategy

    Returns
    -------
    Self
        Validated configuration.
    """
    if self.algorithm_config.algorithm == SupportedAlgorithm.N2V:
        # missing N2V_MANIPULATE
        if not self.data_config.has_n2v_manipulate():
            self.data_config.transforms.append(
                N2VManipulateModel(
                    name=SupportedTransform.N2V_MANIPULATE.value,
                )
            )

        median = SupportedPixelManipulation.MEDIAN.value
        uniform = SupportedPixelManipulation.UNIFORM.value
        strategy = median if self.algorithm_config.model.n2v2 else uniform
        self.data_config.set_N2V2_strategy(strategy)
    else:
        # remove N2V manipulate if present
        if self.data_config.has_n2v_manipulate():
            self.data_config.remove_n2v_manipulate()

    return self

load_configuration(path) #

Load configuration from a yaml file.

Parameters:

Name Type Description Default
path str or Path

Path to the configuration.

required

Returns:

Type Description
Configuration

Configuration.

Raises:

Type Description
FileNotFoundError

If the configuration file does not exist.

Source code in src/careamics/config/configuration_model.py
def load_configuration(path: Union[str, Path]) -> Configuration:
    """
    Load configuration from a yaml file.

    Parameters
    ----------
    path : str or Path
        Path to the configuration.

    Returns
    -------
    Configuration
        Configuration.

    Raises
    ------
    FileNotFoundError
        If the configuration file does not exist.
    """
    # load dictionary from yaml
    if not Path(path).exists():
        raise FileNotFoundError(
            f"Configuration file {path} does not exist in " f" {Path.cwd()!s}"
        )

    dictionary = yaml.load(Path(path).open("r"), Loader=yaml.SafeLoader)

    return Configuration(**dictionary)

save_configuration(config, path) #

Save configuration to path.

Parameters:

Name Type Description Default
config Configuration

Configuration to save.

required
path str or Path

Path to a existing folder in which to save the configuration or to an existing configuration file.

required

Returns:

Type Description
Path

Path object representing the configuration.

Raises:

Type Description
ValueError

If the path does not point to an existing directory or .yml file.

Source code in src/careamics/config/configuration_model.py
def save_configuration(config: Configuration, path: Union[str, Path]) -> Path:
    """
    Save configuration to path.

    Parameters
    ----------
    config : Configuration
        Configuration to save.
    path : str or Path
        Path to a existing folder in which to save the configuration or to an existing
        configuration file.

    Returns
    -------
    Path
        Path object representing the configuration.

    Raises
    ------
    ValueError
        If the path does not point to an existing directory or .yml file.
    """
    # make sure path is a Path object
    config_path = Path(path)

    # check if path is pointing to an existing directory or .yml file
    if config_path.exists():
        if config_path.is_dir():
            config_path = Path(config_path, "config.yml")
        elif config_path.suffix != ".yml" and config_path.suffix != ".yaml":
            raise ValueError(
                f"Path must be a directory or .yml or .yaml file (got {config_path})."
            )
    else:
        if config_path.suffix != ".yml" and config_path.suffix != ".yaml":
            raise ValueError(
                f"Path must be a directory or .yml or .yaml file (got {config_path})."
            )

    # save configuration as dictionary to yaml
    with open(config_path, "w") as f:
        # dump configuration
        yaml.dump(config.model_dump(), f, default_flow_style=False, sort_keys=False)

    return config_path