# base_attached_module

Python API: `luxonis_train.attached_modules.base_attached_module`

The base class of every loss, metric, and visualizer.

[BaseAttachedModule](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/attached_modules/base_attached_module.md)
checks that a module fits the task and the type of its node.
[BaseAttachedModule.get_parameters](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/attached_modules/base_attached_module.md)
selects the inputs of a module from the output packet of the node and the labels, by the parameter names of the module.

## Classes

### BaseAttachedModule

Base class for all modules that attach to a
[BaseNode](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md).

[BaseLoss](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/attached_modules/losses/base_loss.md),
[BaseMetric](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/attached_modules/metrics/base_metric.md),
and
[BaseVisualizer](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/attached_modules/visualizers/base_visualizer.md)
subclass it. A subclass can restrict the nodes that it accepts in two ways:

 * Set the class attribute `supported_tasks`.
 * Annotate `node` in the class body, for example `node: OCRCTCHead`. The constructor then raises
   [IncompatibleError](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/utils/exceptions.md)
   when the node is not an instance of that class. The check reads only the annotations of the nearest class that has annotations.
   Thus the annotations of a subclass hide the `node` annotation of its parent.

The properties that read the node, such as
[n_classes](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/attached_modules/base_attached_module.md),
raise `RuntimeError` when the module has no node.

#### Methods

##### init

```python
def __init__(*, node: BaseNode | None = None, **kwargs):
```

Initialize the module and select its task.

The task of the node becomes the task of the module. Without a node, or with a node that has no task, the only item of
`supported_tasks` becomes the task. In the other cases, the module has no task, and
[task](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/attached_modules/base_attached_module.md)
raises `RuntimeError`.

Parameters

 * `node` (`BaseNode | None`): The node that the module attaches to. The trainer passes it. `None` makes the properties that read
   the node raise `RuntimeError`.
 * `**kwargs`: Keyword arguments forwarded to the next base class. For a metric, it is the `torchmetrics` `Metric`. For a loss or
   a visualizer, it is `torch.nn.Module`, which raises `TypeError` for any keyword argument.

Raises

 * `IncompatibleError`: When the task of the node is not in `supported_tasks`, or when the node is not an instance of the class in
   the `node` annotation.

##### get_parameters

```python
def get_parameters(predictions: Packet[Tensor], labels: Labels | None = None) -> dict[str, Tensor | list[Tensor] | None]:
```

Select the arguments of the module from a batch.

The method reads the parameters of
[BaseLoss.forward](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/attached_modules/losses/base_loss.md),
[BaseMetric.update](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/attached_modules/metrics/base_metric.md),
or
[BaseVisualizer.forward](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/attached_modules/visualizers/base_visualizer.md),
without `self`, `kwargs`, and the canvases of a visualizer. It picks a value for each parameter by its name:

 * A name that starts with `target` selects a label. The part after the first underscore is the label, so `target_boundingbox`
   selects `<task_name>/boundingbox`. A name without an underscore, such as `target`, selects the only label in
   [required_labels](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/attached_modules/base_attached_module.md).
 * A name that starts with `pred` selects the packet key after the first underscore. A name without an underscore, such as
   `predictions`, selects the `main_output` of
   [task](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/attached_modules/base_attached_module.md).
 * Any other name selects the packet key of that name.

`<task_name>` is the `task_name` of
[node](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/attached_modules/base_attached_module.md).
The method clones each selected tensor, and each tensor of a selected list. When a value is missing, a parameter annotated with `|
None` gets `None`. Another parameter with a default value gets no entry, so the default applies.

> **Example**
> A missing optional value becomes `None`. The selected tensor is a copy:

```pycon
>>> import torch
>>> from torch import Tensor
>>> from luxonis_train.attached_modules.losses import BaseLoss
>>> class Loss(BaseLoss, register=False):
...     def forward(
...         self, features: Tensor, scale: Tensor | None = None
...     ) -> Tensor:
...         return features.sum()
>>> packet = {"features": torch.ones(2)}
>>> kwargs = Loss().get_parameters(packet)
>>> kwargs["scale"] is None
True
>>> kwargs["features"] is packet["features"]
False
```

Parameters

 * `predictions` (`Packet[Tensor]`): The output packet of the node.
 * `labels` (`Labels | None`): The labels of the batch, keyed `<task_name>/<label>`. `None` acts as an empty dictionary.

Returns

 * `dict[str, Tensor | list[Tensor] | None]`: The values keyed by parameter name, ready to pass as keyword arguments.

Raises

 * `RuntimeError`: When a parameter without a default value gets no value. Also when a `target` name has no underscore and the
   task does not require exactly one label. Also when a name needs a node or a task that the module does not have.
 * `TypeError`: When a value does not match the annotation of its parameter.

#### Attributes

##### classes

The class indices of the node task, keyed by class name.

The value is
[BaseNode.classes](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
of
[node](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/attached_modules/base_attached_module.md),
a new `bidict`.

Raises

 * `RuntimeError`: When the module has no node, or when the node got no `dataset_metadata`.
 * `ValueError`: When the dataset has no task with the `task_name` of the node.

##### current_epoch

The number of the current training epoch, from `0`.

The value comes from
[node](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/attached_modules/base_attached_module.md).
[LuxonisLightningModule](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/lightning/luxonis_lightning.md)
sets it on the node at the start of each training epoch.

Raises

 * `RuntimeError`: When the module has no node.

##### n_classes

The number of classes of the node task.

The value is
[BaseNode.n_classes](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
of
[node](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/attached_modules/base_attached_module.md).

Raises

 * `RuntimeError`: When the module has no node, or when the node got neither `n_classes` nor `dataset_metadata`.
 * `ValueError`: When the dataset has no task with the `task_name` of the node.

##### n_keypoints

The number of keypoints of the node task.

The value is
[BaseNode.n_keypoints](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
of
[node](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/attached_modules/base_attached_module.md).
It is `0` when the dataset has no keypoints for the task of the node.

Raises

 * `RuntimeError`: When the module has no node, or when the node got neither `n_keypoints` nor `dataset_metadata`.

##### name

The class name of the module.

It is not the alias of the module in the config. The error messages of the module use it.

##### node

The node that the module attaches to.

Raises

 * `RuntimeError`: When the constructor got no node.

##### original_in_shape

The shape of the model input image, `[C, H, W]`.

The value is
[BaseNode.original_in_shape](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
of
[node](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/attached_modules/base_attached_module.md).
The shape does not include the batch dimension.

Raises

 * `RuntimeError`: When the module has no node, or when the node got no `original_in_shape`.

##### required_labels

The labels that the task of the module requires.

The base implementation returns the
[Task.required_labels](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/tasks.md)
of
[task](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/attached_modules/base_attached_module.md).
A `target` parameter without an underscore selects the only label of this set.

Raises

 * `RuntimeError`: When the module has no task.

##### supported_tasks

The tasks that the module supports. The constructor raises
[IncompatibleError](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/utils/exceptions.md)
when the task of the node is not in the sequence. When the module gets no task from its node and the sequence holds one task, that
task becomes the task of the module. `None` accepts a node with any task.

##### task

The task of the module.

The constructor selects it from the node or from `supported_tasks`.

Raises

 * `RuntimeError`: When the module has no task.
