# blocks

Python API: `luxonis_train.nodes.backbones.ghostfacenet.blocks`

The ghost modules of GhostFaceNet, which produce part of the feature maps with cheap operations instead of full convolutions.

## Classes

### AttentionGhostModuleV2

Ghost module with a gate from a decoupled attention branch.

The attention branch reads the input of the module. It runs a convolution with the kernel size and the stride of the primary
convolution, a `1x5` and a `5x1` depthwise convolution, a `2x2` average pool with stride 2, and a sigmoid. The convolutions of the
branch have a batch norm and no activation. GhostNetV2 calls this branch DFC attention. A nearest interpolation resizes the gate
to the output size, and the module multiplies the ghost features by the gate.

> **Example**
> ```pycon
>>> import torch
>>> module = AttentionGhostModuleV2(4, 8)
>>> module(torch.zeros(1, 4, 7, 7)).shape
torch.Size([1, 8, 7, 7])
```

#### Methods

##### init

```python
def __init__(in_channels: int, out_channels: int, kernel_size: int = 1, ratio: int = 2, dw_size: int = 3, stride: int = 1,
use_prelu: bool = True):
```

Build the ghost convolutions and the attention branch.

Parameters

 * `in_channels` (`int`): Number of input channels.
 * `out_channels` (`int`): Number of output channels.
 * `kernel_size` (`int`): Size of the primary kernel and of the first kernel of the attention branch. The padding is `kernel_size // 2`.
 * `ratio` (`int`): The ratio of `out_channels` to the channels of the primary convolution.
 * `dw_size` (`int`): Size of the cheap depthwise kernel. The padding is `dw_size // 2`.
 * `stride` (`int`): Stride of the primary convolution and of the first convolution of the attention branch.
 * `use_prelu` (`bool`): Whether the primary and the cheap convolutions end with `torch.nn.PReLU`. The attention branch never has an activation before the sigmoid.

##### forward

```python
def forward(x: Tensor) -> Tensor:
```

Multiply the ghost features by the attention gate.

Parameters

 * `x` (`Tensor`): Input of shape `[B, in_channels, H, W]`.

Returns

 * `Tensor`: Output of shape `[B, out_channels, H', W']`. The stride of the primary convolution sets `H'` and `W'`. Each value is the ghost feature times a gate between `0` and `1`.

#### Attributes

##### short_conv

### GhostBottleneckLayer

Stage of [GhostBottleneckV2](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/backbones/ghostfacenet/blocks.md) blocks with one ghost module mode.

The five lists give one value for each block. Each block reads the output of the block before it. The layer multiplies the expansion and output channels by `width_multiplier`. It then rounds each count to the nearest multiple of 4, with a minimum of 4. A count that rounds below 90% of its value goes up by 4.

> **Example**
> ```pycon
>>> import torch
>>> layer = GhostBottleneckLayer(
...     width_multiplier=1,
...     input_channel=16,
...     kernel_sizes=[3, 3],
...     expand_sizes=[48, 72],
...     output_channels=[24, 24],
...     se_ratios=[0.0, 0.25],
...     strides=[2, 1],
...     mode="attention",
... )
>>> len(layer), layer.output_channel
(2, 24)
>>> layer(torch.zeros(1, 16, 8, 8)).shape
torch.Size([1, 24, 4, 4])
```

#### Methods

##### init

```python
def __init__(width_multiplier: int, input_channel: int, kernel_sizes: list[int], expand_sizes: list[int], output_channels: list[int], se_ratios: list[float], strides: list[int], mode: Literal['original', 'attention']):
```

Build one
[GhostBottleneckV2](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/backbones/ghostfacenet/blocks.md)
for each entry of the lists.

Parameters

 * `width_multiplier` (`int`): The scale of `expand_sizes` and `output_channels`.
 * `input_channel` (`int`): Number of input channels of the first block. The layer does not scale it.
 * `kernel_sizes` (`list[int]`): The `kernel_size` of each block.
 * `expand_sizes` (`list[int]`): The `hidden_channels` of each block, before `width_multiplier`.
 * `output_channels` (`list[int]`): The `out_channels` of each block, before `width_multiplier`.
 * `se_ratios` (`list[float]`): The `se_ratio` of each block.
 * `strides` (`list[int]`): The `stride` of each block.
 * `mode` (`Literal['original', 'attention']`): The `mode` of all blocks.

Raises

 * `ValueError`: When the five lists do not have the same length.

#### Attributes

##### output_channel

Number of output channels of the last block. It is `input_channel` when the lists are empty.

### GhostBottleneckV2

Ghost bottleneck of GhostFaceNetsV2 with a shortcut.

The main path has these layers:

 * A ghost module with `torch.nn.PReLU` expands `in_channels` to `hidden_channels`.
 * For a `stride` above `1`, a depthwise convolution with a batch norm and no activation reduces the spatial size.
 * For a `se_ratio` above `0`, a
   [SqueezeExciteBlock](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/blocks/blocks.md)
   with a hard sigmoid and `torch.nn.PReLU` scales the channels.
 * An
   [OriginalGhostModuleV2](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/backbones/ghostfacenet/blocks.md)
   without an activation projects to `out_channels`.

The shortcut is `torch.nn.Identity` when `in_channels` equals `out_channels` and `stride` is `1`. Otherwise it is a depthwise
convolution with `kernel_size` and `stride`, then a `1x1` convolution, each with a batch norm. The block adds the shortcut to the
main path.

> **Example**
> ```pycon
>>> import torch
>>> block = GhostBottleneckV2(
...     8, 16, 8, stride=2, se_ratio=0.25, mode="attention"
... )
>>> block(torch.zeros(1, 8, 8, 8)).shape
torch.Size([1, 8, 4, 4])
>>> GhostBottleneckV2(8, 16, 8, mode="original").shortcut
Identity()
```

#### Methods

##### init

```python
def __init__(in_channels: int, hidden_channels: int, out_channels: int, kernel_size: int = 3, stride: int = 1, se_ratio: float =
0.0, *, mode: Literal['original', 'attention']):
```

Build the main path and the shortcut.

Parameters

 * `in_channels` (`int`): Number of input channels.
 * `hidden_channels` (`int`): Number of channels after the expansion.
 * `out_channels` (`int`): Number of output channels.
 * `kernel_size` (`int`): Size of the depthwise kernels of the main path and of the shortcut. The padding is `(kernel_size - 1) // 2`.
 * `stride` (`int`): Stride of both depthwise convolutions.
 * `se_ratio` (`float`): The ratio of the squeeze-and-excite channels to `hidden_channels`. The block rounds the result to a multiple of 4. `0` or less adds no [SqueezeExciteBlock](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/blocks/blocks.md).
 * `mode` (`Literal['original', 'attention']`): The ghost module of the expansion. `"original"` selects [OriginalGhostModuleV2](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/backbones/ghostfacenet/blocks.md), and `"attention"` selects [AttentionGhostModuleV2](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/backbones/ghostfacenet/blocks.md).

##### forward

```python
def forward(x: Tensor) -> Tensor:
```

Apply the main path and add the shortcut.

Parameters

 * `x` (`Tensor`): Input of shape `[B, in_channels, H, W]`.

Returns

 * `Tensor`: Output of shape `[B, out_channels, H', W']`. For an odd `kernel_size`, `H'` and `W'` are `H` and `W` divided by `stride` and rounded up.

#### Attributes

##### bn_dw

##### conv_dw

##### ghost1

##### ghost2

##### se

##### shortcut

### OriginalGhostModuleV2

Ghost module that makes part of its output with a cheap operation.

A primary convolution makes `ceil(out_channels / ratio)` channels. A depthwise convolution, the cheap operation, makes `ratio - 1` channels from each of them. The module concatenates both results and keeps the first `out_channels` channels. Both convolutions have a batch norm.

> **Example**
> ```pycon
>>> import torch
>>> module = OriginalGhostModuleV2(4, 7, ratio=3)
>>> module.primary_conv.out_channels
3
>>> module.cheap_operation.out_channels
6
>>> module(torch.zeros(1, 4, 8, 8)).shape
torch.Size([1, 7, 8, 8])
```

#### Methods

##### init

```python
def __init__(in_channels: int, out_channels: int, kernel_size: int = 1, ratio: int = 2, dw_size: int = 3, stride: int = 1, use_prelu: bool = True):
```

Build the primary and the cheap convolutions.

Parameters

 * `in_channels` (`int`): Number of input channels.
 * `out_channels` (`int`): Number of output channels.
 * `kernel_size` (`int`): Size of the primary kernel. The padding is `kernel_size // 2`.
 * `ratio` (`int`): The ratio of `out_channels` to the channels of the primary convolution.
 * `dw_size` (`int`): Size of the depthwise kernel. The padding is `dw_size // 2`.
 * `stride` (`int`): Stride of the primary convolution.
 * `use_prelu` (`bool`): Whether both convolutions end with `torch.nn.PReLU`. When `False`, they have no activation.

##### forward

```python
def forward(x: Tensor) -> Tensor:
```

Concatenate the primary and the cheap features.

Parameters

 * `x` (`Tensor`): Input of shape `[B, in_channels, H, W]`.

Returns

 * `Tensor`: Output of shape `[B, out_channels, H', W']`. The stride of the primary convolution sets `H'` and `W'`.

#### Attributes

##### cheap_operation

##### primary_conv
