# base_node

Python API: `luxonis_train.nodes.base_node`

The base class every node inherits.

[BaseNode](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
gives a node the shapes of its inputs, so that the node can size its layers. It maps the input packets to the parameters of
`forward`. It also builds a node from a named variant, loads pretrained weights, and switches export mode.

## Classes

### BaseNode

Base class for all nodes of the model graph.

A node is a `torch.nn.Module` that reads packets and returns a packet. A packet is a dictionary that maps an output name to a
tensor or to a list of tensors. The model calls
[run](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
with one packet for each input of the node. The packet of an input node is its output. The packet of a loader input holds the
tensor in a list under the key `"features"`.
[run](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
passes the packet values to
[forward](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
and returns the result as a packet.

Every subclass registers itself in
[luxonis_train.registry.NODES](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/registry.md)
under its class name, so a config refers to the node by that name. A `register_name` in the class statement replaces the class
name. Put `register=False` in the class statement to skip the registration.

A subclass must implement
[forward](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md).
It can also do these steps:

 * Set the class attributes `attach_index` and `task`.
 * Override
   [get_variants](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
   to declare variants.
 * Override
   [get_weights_url](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
   to offer pretrained weights.
 * Override
   [initialize_weights](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
   to initialize its own layers.
 * Annotate a property in the class body, for example `in_channels: int`. The constructor then compares the value of the property
   with the annotation. On a mismatch, it raises
   [IncompatibleError](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/utils/exceptions.md).
   The constructor skips the check when the property raises `RuntimeError`. Any other error of the property goes out of the
   constructor. The check reads only the annotations of the nearest class that has annotations. Thus the annotations of a subclass
   hide the annotations of its parent.

> **Example**
> A node that sizes its layer from the input shapes. The `register=False` keeps the example out of the registry.

```pycon
>>> import torch
>>> from torch import Size, Tensor, nn
>>> from luxonis_train.nodes import BaseNode
>>> class Conv(BaseNode, register=False):
...     def __init__(self, **kwargs):
...         super().__init__(**kwargs)
...         self.conv = nn.Conv2d(self.in_channels, 8, kernel_size=1)
...
...     def forward(self, x: Tensor) -> Tensor:
...         return self.conv(x)
>>> node = Conv(input_shapes=[{"features": [Size([2, 3, 32, 32])]}])
>>> node.attach_index, node.in_channels
(-1, 3)
>>> packet = node.run([{"features": [torch.zeros(2, 3, 32, 32)]}])
>>> packet["features"].shape
torch.Size([2, 8, 32, 32])
```

#### Methods

##### init

```python
def __init__(*, input_shapes: list[Packet[Size]] | None = None, original_in_shape: Size | None = None, dataset_metadata: DatasetMetadata | None = None, n_classes: int | None = None, n_keypoints: int | None = None, in_sizes: Size | list[Size] | None = None, remove_on_export: bool = False, export_output_names: list[str] | None = None, attach_index: AttachIndexType | None = None, task_name: str | None = None, weights: str | Literal['download', 'yolo', 'none'] | None = None):
```

Initialize the node.

All arguments are keyword-only and optional. Properties that depend on missing metadata raise `RuntimeError` when accessed.

Parameters

 * `input_shapes` (`list[Packet[Size]] | None`): One shape packet for each input of the node, in the order of the inputs. The
   shape properties, such as
   [in_channels](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md),
   read it.
 * `original_in_shape` (`Size | None`): The shape of the model input image, `[C, H, W]`, without the batch dimension.
 * `dataset_metadata` (`DatasetMetadata | None`): The metadata of the dataset.
   [n_classes](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md),
   [n_keypoints](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md),
   [classes](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md),
   and
   [class_names](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
   read it.
 * `n_classes` (`int | None`): The number of classes. When it is set,
   [n_classes](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
   returns it and does not read `dataset_metadata`.
 * `n_keypoints` (`int | None`): The number of keypoints. When it is set,
   [n_keypoints](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
   returns it and does not read `dataset_metadata`.
 * `in_sizes` (`Size | list[Size] | None`): The sizes of the attached inputs. When it is set,
   [in_sizes](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
   returns it and does not read `input_shapes`.
 * `remove_on_export` (`bool`): When `True`, the model skips the node in export mode, so the exported model does not contain the
   node.
 * `export_output_names` (`list[str] | None`): The names of the node outputs in the exported model. See
   [export_output_names](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
   for how the export uses them. `None` keeps the default names.
 * `attach_index` (`AttachIndexType | None`): The output of the input node that the node reads. A value other than `None` replaces
   the class attribute and logs a warning. See
   [attach_index](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
   for the accepted values.
 * `task_name` (`str | None`): The dataset task of the node. It selects the classes and the keypoints in `dataset_metadata`.
   `None` becomes `""`.
 * `weights` (`str | Literal['download', 'yolo', 'none'] | None`): The source or the initialization method of the weights. The
   variant metaclass calls `__post_init__` after the constructor. That step reads the value: * `"download"` calls
   [load_checkpoint](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md),
   which takes the URL from
   [get_weights_url](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md).
    * A string that contains `"://"` calls
      [load_checkpoint](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
      with that URL.
    * Any other string goes to
      [initialize_weights](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
      as the method. A local checkpoint path also goes there, and the base implementation does not load it.
    * `None` and `""` act as `"none"`.

Raises

 * `AssertionError`: When
   [attach_index](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
   is `None` and `forward` has no parameters.
 * `IncompatibleError`: When a property that the class body annotates has a value of a different type.

##### export.setter

```python
def export.setter(mode: bool):
```

Switch export mode on or off with
[set_export_mode](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md).

##### forward

```python
def forward(inputs: Tensor | list[Tensor] | Packet[Tensor] | list[Packet[Tensor]]) -> Tensor | list[Tensor] | Packet[Tensor]:
```

Compute the outputs of the node.

A subclass must implement it.
[run](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
reads the name and the type annotation of each parameter to decide what the parameter gets. Annotate each parameter with one of
the four types of `inputs`. See
[run](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
for the rules.

Parameters

 * `inputs` (`Tensor | list[Tensor] | Packet[Tensor] | list[Packet[Tensor]]`): The input of the node. An implementation can rename
   the parameter and add more parameters.

Returns

 * `Tensor | list[Tensor] | Packet[Tensor]`: The outputs of the node.
   [run](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
   puts a tensor or a list of tensors into a packet.

##### get_attached

```python
def get_attached(value: list[T] | T) -> list[T] | T:
```

Select the elements of a list that
[attach_index](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
names.

A value that is not a list passes unchanged. The index must then be `None`, `-1`, or `0`. For a list, the index selects:

 * With `"all"`, the whole list.
 * With an integer, one element. A negative index counts from the end.
 * With a pair `(i, j)` or a triple `(i, j, k)`, a slice from `i` to `j` with the step `k`. The slice includes `i` and leaves out
   `j`, as in Python. A negative index counts from the end. The default step is `-1` when `i > j` and the two indices are both
   negative or both non-negative. Otherwise, it is `1`.

Exception: when `i` and `j` are both negative and `i < j`, the range leaves out `i` and includes `j`. The step is then always `1`.
Thus `(-3, -1)` selects the last two elements, not the Python slice `[-3:-1]`.

> **Example**
> ```pycon
>>> from torch import Tensor
>>> from luxonis_train.nodes import BaseNode
>>> class Node(BaseNode, register=False):
...     def forward(self, x: Tensor) -> Tensor:
...         return x
>>> node = Node()
>>> node.get_attached([1, 2, 3, 4, 5])
5
>>> node.attach_index = (1, -1)
>>> node.get_attached([1, 2, 3, 4, 5])
[2, 3, 4]
>>> node.attach_index = (-3, -1)
>>> node.get_attached([1, 2, 3, 4, 5])
[4, 5]
```

Parameters

 * `value` (`list[T] | T`): A list of tensors or sizes, or a single tensor or size.

Returns

 * `list[T] | T`: One element for an integer index, a list for `"all"` or a tuple, or `value` itself when it is not a list.

Raises

 * `ValueError`: When `value` is not a list and the index is not `None`, `-1`, or `0`. Also when an integer index is `len(value)` or larger.
 * `RuntimeError`: When `value` is a list and the index is `None`.

##### get_variants

```python
def get_variants() -> tuple[str, dict[str, Kwargs]]:
```

Return the default variant name and the variants of the node.

A node with variants overrides this static method. A call such as `Node(variant="n")` selects a variant, and `"default"` selects the default variant. The variant metaclass then passes the parameters of the variant to the constructor. An argument that the call gives explicitly replaces the variant parameter of the same name. A variant name that is not in the dictionary makes the metaclass raise `ValueError`.

> **Example**
> ```pycon
>>> from torch import Tensor
>>> from luxonis_train.nodes import BaseNode
>>> class Node(BaseNode, register=False):
...     def __init__(self, width: int = 1, **kwargs):
...         super().__init__(**kwargs)
...         self.width = width
...
...     def forward(self, x: Tensor) -> Tensor:
...         return x
...
...     @staticmethod
...     def get_variants():
...         return "n", {"n": {"width": 8}, "s": {"width": 16}}
>>> node = Node(variant="default")
>>> node.variant, node.width
('n', 8)
>>> Node(variant="s").width
16
>>> Node().width
1
```

Returns

 * `tuple[str, dict[str, Kwargs]]`: The name of the default variant, and a dictionary that maps each variant name to its
   constructor keyword arguments.

Raises

 * `NotImplementedError`: When the node has no variants. The base implementation always raises it.

##### get_weights_url

```python
def get_weights_url(self) -> str:
```

Return the URL of the pretrained weights of the node.

A node with pretrained weights overrides this method. The base implementation raises `NotImplementedError`, which means that the
node has no pretrained weights.
[load_checkpoint](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
calls the method when it gets no checkpoint, for example for `weights="download"`.

The URL can contain these placeholders:

 * `{github}` becomes `https://github.com/luxonis/luxonis-train/releases/download/v0.3.10-beta/`. The version is fixed. The
   installed version does not change it.
 * `{github:v0.3.0}` selects the release `v0.3.0` instead. The version needs three numbers and can have a suffix, as in
   `v0.3.0-beta`.
 * `{variant}` becomes the name of the variant that built the node. The node must come from a variant.

The file at the URL must hold the state dictionary of the node under the `"state_dict"` key. The keys of that dictionary must be
the parameter and buffer names of the node.

Returns

 * `str`: The URL of the checkpoint. It can contain the placeholders.

Raises

 * `NotImplementedError`: When the node has no pretrained weights.

##### initialize_weights

```python
def initialize_weights(method: Literal['yolo', 'none'] | str | None = None):
```

Initialize the weights of the node.

The node calls it after construction with the `weights` argument as `method`, unless `weights` asks for a checkpoint. A subclass
overrides it to initialize its own layers.

The base implementation knows one method, `"yolo"`. It sets `eps` to `0.001` and `momentum` to `0.03` in every
`torch.nn.BatchNorm2d`. It also sets `inplace` to `True` in every `Hardswish`, `LeakyReLU`, `ReLU`, `ReLU6`, and `SiLU`
activation. Other values change nothing.

> **Example**
> The `weights` argument of the constructor selects the method.

```pycon
>>> from torch import Tensor, nn
>>> from luxonis_train.nodes import BaseNode
>>> class Node(BaseNode, register=False):
...     def __init__(self, **kwargs):
...         super().__init__(**kwargs)
...         self.bn = nn.BatchNorm2d(4)
...
...     def forward(self, x: Tensor) -> Tensor:
...         return self.bn(x)
>>> Node().bn.eps
1e-05
>>> node = Node(weights="yolo")
>>> node.bn.eps, node.bn.momentum
(0.001, 0.03)
```

Parameters

 * `method` (`Literal['yolo', 'none'] | str | None`): The name of the initialization method. `None` and `"none"` change nothing.

##### load_checkpoint

```python
def load_checkpoint(ckpt: str | dict[str, Tensor] | None = None, *, strict: bool = True):
```

Load a checkpoint into the node.

For a file, the method logs the path or URL.
[safe_download](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/utils/general.md)
copies a remote file into the local cache first. When the download fails, the method logs a warning and leaves the weights
unchanged. The method reads the file with `torch.load` on the CPU and with `weights_only=False`. Load only trusted files, because
the file can run code when it loads. After the load, the method logs an info message through the standard `logging` module.

Parameters

 * `ckpt` (`str | dict[str, Tensor] | None`): A state dictionary, or the local path or URL of a `.ckpt` file. The file must hold
   the state dictionary under the `"state_dict"` key. `None` or `""` takes the URL from
   [get_weights_url](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md).
 * `strict` (`bool`): Whether the keys of the state dictionary must match the keys of the node exactly. The value goes to
   `torch.nn.Module.load_state_dict`. With `True`, that method raises `RuntimeError` when the keys differ.

Raises

 * `RuntimeError`: When `ckpt` is an empty dictionary.
 * `ValueError`: When `ckpt` is `None` and the node does not override
   [get_weights_url](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md),
   or when the URL uses `{variant}` and no variant built the node.

##### run

```python
def run(inputs: list[Packet[Tensor]]) -> Packet[Tensor]:
```

Run the node on the packets of its inputs.

The method gives each `forward` parameter a value, calls the node, and puts the result into a packet. The type annotation and the
name of a parameter decide its value:

 * A `list[Packet[Tensor]]` parameter gets all input packets. It must be the only parameter.
 * A `Packet[Tensor]` parameter gets the input packet at the position of the parameter.
 * A `Tensor` or `list[Tensor]` parameter can have the name `x`, `y`, or `z`, or a name that starts with `input`. It then gets the
   `"features"` entry of one input packet. `x`, `y`, and `z` read the packets 0, 1, and 2. A number after `input` or `inputs`, as
   in `input_1`, selects that packet. Other names read packet 0. A list entry goes through
   [get_attached](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md).
 * A `Tensor` or `list[Tensor]` parameter with another name gets the entry with the same key, unchanged. Special case: no packet
   has the key, the node has one input packet, and `forward` has one parameter. Then the parameter gets the first entry of that
   packet through
   [get_attached](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md),
   and the method logs a warning.

`forward` can return a packet, a tensor, or a list of tensors. The method puts a tensor or a list under the key
`task.main_output`, or under `"features"` when
[task](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
is `None`.

> **Example**
> ```pycon
>>> import torch
>>> from torch import Tensor
>>> from luxonis_train.nodes import BaseNode
>>> class Add(BaseNode, register=False):
...     attach_index = -1
...
...     def forward(self, x: Tensor, y: Tensor) -> Tensor:
...         return x + y
>>> packets = [
...     {"features": [torch.ones(2)]},
...     {"features": [torch.ones(2)]},
... ]
>>> Add().run(packets)["features"].tolist()
[2.0, 2.0]
```

Parameters

 * `inputs` (`list[Packet[Tensor]]`): One packet for each input of the node, in the order of the inputs.

Returns

 * `Packet[Tensor]`: The outputs of the node, for example `{"features": [feature_map_1, feature_map_2]}`.

Raises

 * `TypeError`: When a `forward` parameter has an annotation other than the four types above. The call to `forward` also raises it when a required parameter gets no value.
 * `RuntimeError`: When a `list[Packet[Tensor]]` parameter is not the only parameter, or when the input packets are too few. Also when a parameter that reads the `"features"` entry gets a packet without that key. Also when an entry has the wrong type, or when two packets have the same key. Also when [get_attached](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md) gets a list and [attach_index](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md) is `None`.
 * `ValueError`: When `forward` returns a value of another type. Also when [attach_index](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md) does not fit an entry that goes through [get_attached](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md).

##### set_export_mode

```python
def set_export_mode(/, mode: bool):
```

Switch export mode on or off.

The method sets [export](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md). Then it visits the node and all its submodules. With `True`, it calls `reparameterize` on each [Reparameterizable](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/blocks/reparameterizable.md) module. With `False`, it calls `restore` on each of them. It logs every call at the debug level.

Parameters

 * `mode` (`bool`): `True` to switch export mode on, `False` to switch it off.

#### Attributes

##### attach_index

The output or outputs of the input node that the node reads. [get_attached](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md) applies it. The value is an integer index, a tuple of two or three integers for a range, or `"all"` for every output. `-1` is the last output.

When a subclass leaves it `None`, the constructor infers it from `forward`. A `forward` with one parameter annotated `Tensor` gives `-1`. One parameter annotated `list[Tensor]` gives `"all"`. For any other `forward` with parameters, the constructor logs a warning and the index stays `None`.

##### class_names

The class names of the node task, sorted by class index.

Raises

 * `RuntimeError`: When the constructor got no `dataset_metadata`.
 * `ValueError`: When the dataset has no task named [task_name](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md).

##### classes

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

The value always comes from [dataset_metadata](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md) for [task_name](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md). The `n_classes` constructor argument does not change it. The value is a new `bidict`. Its `inverse` maps the class indices to the class names.

Raises

 * `RuntimeError`: When the constructor got no `dataset_metadata`.
 * `ValueError`: When the dataset has no task named [task_name](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md).

##### current_epoch

The number of the current training epoch, from `0`. [LuxonisLightningModule](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/lightning/luxonis_lightning.md) sets it at the start of each training epoch.

##### dataset_metadata

The metadata of the dataset.

Raises

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

##### export

Whether export mode is on.

A node reads it in `forward` to return the outputs of the exported model. An assignment calls [set_export_mode](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md).

##### export_output_names

The names of the node outputs in the exported model.

The base implementation returns the `export_output_names` constructor argument. `None` keeps the default names.

The ONNX export uses the names only when their number matches the number of node outputs. Otherwise, it logs a warning and keeps the default names. The NN Archive of a head lists the names as the head outputs.

##### in_channels

The number of channels of the attached inputs.

It is the third dimension from the end of [in_sizes](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md), so a shape with or without the batch dimension gives the same value. A list of sizes gives a list of channel counts.

Raises

 * `RuntimeError`: When [in_sizes](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md) cannot find the input sizes.
 * `ValueError`: When [attach_index](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md) does not fit the sizes.

##### in_height

The height of the attached inputs.

It is the second dimension from the end of [in_sizes](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md). A list of sizes gives a list of heights.

Raises

 * `RuntimeError`: When [in_sizes](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md) cannot find the input sizes.
 * `ValueError`: When [attach_index](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md) does not fit the sizes.

##### in_sizes

The sizes of the attached inputs.

The property uses the first rule that applies:

 1. The `in_sizes` constructor argument, when it is set.
 2. The `"features"` entry of the only input packet.
 3. The only entry of that packet.
 4. The entries of that packet whose keys match the names of the `forward` parameters. Their sizes must be equal, and the property uses the first one.

Rules 2 to 4 pass the entry through [get_attached](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md). The result is a single size for an integer [attach_index](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md), and a list of sizes for `"all"` or a range. A node with more than one input, or with shapes that the rules do not fit, must read [input_shapes](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md) instead.

> **Example**
> ```pycon
>>> from torch import Size, Tensor
>>> from luxonis_train.nodes import BaseNode
>>> class Node(BaseNode, register=False):
...     def forward(self, x: list[Tensor]) -> list[Tensor]:
...         return x
>>> shapes = [
...     {"features": [Size([2, 8, 64, 64]), Size([2, 16, 32, 32])]}
... ]
>>> node = Node(input_shapes=shapes)
>>> node.attach_index
'all'
>>> node.in_sizes
[torch.Size([2, 8, 64, 64]), torch.Size([2, 16, 32, 32])]
>>> node.in_channels, node.in_height, node.in_width
([8, 16], [64, 32], [64, 32])
```

Raises

 * `RuntimeError`: When `input_shapes` is missing or does not hold exactly one packet. Also when no key matches a `forward`
   parameter, or when the matching sizes differ. Also when
   [attach_index](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
   is `None` and the entry is a list.
 * `ValueError`: When
   [attach_index](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
   does not fit the sizes.

##### in_width

The width of the attached inputs.

It is the last dimension of
[in_sizes](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md).
A list of sizes gives a list of widths.

Raises

 * `RuntimeError`: When
   [in_sizes](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
   cannot find the input sizes.
 * `ValueError`: When
   [attach_index](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
   does not fit the sizes.

##### input_shapes

The shape packets of the node inputs, one for each input.

The model takes the shapes from a run on zero tensors with a batch size of 2, so the shapes include the batch dimension.

Raises

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

##### n_classes

The number of classes of the node task.

The `n_classes` constructor argument comes first. Without it, the value comes from
[dataset_metadata](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
for
[task_name](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md).

Raises

 * `RuntimeError`: When the constructor got neither `n_classes` nor `dataset_metadata`.
 * `ValueError`: When the dataset has no task named
   [task_name](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md).

##### n_keypoints

The number of keypoints of the node task.

The `n_keypoints` constructor argument comes first. Without it, the value comes from
[dataset_metadata](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
for
[task_name](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md).
It is `0` when the dataset has no keypoints for that task.

Raises

 * `RuntimeError`: When the constructor got neither `n_keypoints` nor `dataset_metadata`.

##### name

The class name of the node.

It is not the alias of the node in the config.

##### original_in_shape

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

The shape does not include the batch dimension.

Raises

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

##### remove_on_export

Whether the model skips the node in export mode.

The exported model then does not contain the node.

##### T

`Tensor` or `Size`.

##### task

The task of the node. A head sets it. When `forward` returns a tensor or a list of tensors,
[run](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
puts the result under the key `task.main_output`. When the task is `None`, the key is `"features"`.

##### task_name

The dataset task of the node. It is `""` when the constructor gets no `task_name`.

##### variant

The name of the variant that built the node.

The variant metaclass sets it when a call selects a variant of a node that overrides
[get_variants](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md).
A `"default"` variant resolves to the name of the default variant.

Raises

 * `AttributeError`: When no variant built the node. This occurs for a `variant` of `"none"` or `None`, and for `"default"` on a
   node without variants. Thus `hasattr(node, "variant")` returns `False`.
