# ghostfacenet_head

Python API: `luxonis_train.nodes.heads.ghostfacenet_head`

The embedding head of GhostFaceNet.

## Classes

### GhostFaceNetHead

GhostFaceNet embedding head.

 * `Inputs:`: * `inputs` (`Tensor`): [B, C, ⌈H ⁄ 32⌉, ⌈W ⁄ 32⌉]
 * `Outputs:`: * `embeddings` (`Tensor`): [B, D], where D is `embedding_size`

> **References**
> * Source: Adapted from [Hazqeel09/ellzaf_ml](https://github.com/Hazqeel09/ellzaf_ml) (MIT).
 * License: MIT

> **Notes**
> H and W are the height and the width of the model input. The last output of the [GhostFaceNet](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/backbones/ghostfacenet/ghostfacenet.md) backbone has this size. The head applies these layers in order:

 * A depthwise
   [ConvBlock](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/blocks/blocks.md)
   with batch norm and no activation. Its kernel has the size of the input map, so the output is `1x1`.
 * A dropout layer.
 * A `1x1` convolution without bias to D channels.
 * A flatten step and a 1D batch norm.

`forward` does not check the mode, so export mode also gives the embeddings. The input map must have exactly the size above. A map
of another size makes a layer raise `RuntimeError`. In training mode, a batch of one image makes the batch norm of the depthwise
[ConvBlock](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/blocks/blocks.md)
raise `ValueError`.

 * `Variants:`: None. Configure the node through `params`.

> **See Also**
> * [The GhostFaceNetsV2 code in ellzaf_ml](https://github.com/Hazqeel09/ellzaf_ml/blob/main/ellzaf_ml/models/ghostfacenetsv2.py)
 * [GhostFaceNets: Lightweight Face Recognition Model From Cheap
   Operations](https://www.researchgate.net/publication/369930264_GhostFaceNets_Lightweight_Face_Recognition_Model_from_Cheap_Operations)

> **Example**
> A node entry in the `model.nodes` section of a config:

```yaml
- name: GhostFaceNetHead
  inputs: [GhostFaceNet]
```

 * `Compatible with:`: * Attach index: `-1`, the last output of the input node
    * Required labels: `metadata/id`
    * Used by:
      [EmbeddingsModel](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/config/predefined_models/embeddings/v1/model.md)
    * Losses: * `AngularLoss`
       * `CircleLoss`
       * `ContrastiveLoss`
       * `DynamicSoftMarginLoss`
       * `FastAPLoss`
       * `GeneralizedLiftedStructureLoss`
       * `HistogramLoss`
       * `InstanceLoss`
       * `IntraPairVarianceLoss`
       * `LiftedStructureLoss`
       * `MarginLoss`
       * `MultiSimilarityLoss`
       * `NCALoss`
       * `NPairsLoss`
       * `NTXentLoss`
       * `PNPLoss`
       * `RankedListLoss`
       * `SignalToNoiseRatioContrastiveLoss`
       * `SupConLoss`
       * `ThresholdConsistentMarginLoss`
       * `TripletMarginLoss`
       * `TupletMarginLoss`
    * Metrics: *
      [ClosestIsPositiveAccuracy](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/attached_modules/metrics/embedding_metrics.md)
       * [MedianDistances](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/attached_modules/metrics/embedding_metrics.md)
    * Visualizers:
      [EmbeddingsVisualizer](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/attached_modules/visualizers/embeddings_visualizer.md)

#### Methods

##### init

```python
def __init__(embedding_size: int = 512, cross_batch_memory_size: int | None = None, dropout: float = 0.2, **kwargs):
```

Build the layers of the head.

The constructor stores `embedding_size` and `cross_batch_memory_size` in attributes of the same names. The embedding losses read
both attributes from the node. The embedding metrics read only `cross_batch_memory_size`. The kernel of the depthwise convolution
is ⌈H ⁄ 32⌉×⌈W ⁄ 32⌉, with H and W from `original_in_shape`.

Parameters

 * `embedding_size` (`int`): The number of values in each embedding. It is the number of output channels of the `1x1` convolution.
 * `cross_batch_memory_size` (`int | None`): The maximum number of the newest embeddings that the embedding losses and metrics
   keep in memory across batches. `None` turns this memory off. A loss that `CrossBatchMemory` does not support logs a warning and
   ignores the value. The head itself does not read the value.
 * `dropout` (`float`): The probability that the dropout layer sets a value to zero in training mode, in `[0, 1]`.
 * `**kwargs`: Keyword arguments for
   [BaseNode](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md).
   They must hold `original_in_shape`, and `input_shapes` or `in_sizes`.

##### forward

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

Compute the embeddings of a batch of feature maps.

> **Example**
> A model input of `100x100` pixels gives a `4x4` map, because ⌈100 ⁄ 32⌉ = 4:

```pycon
>>> import torch
>>> from torch import Size
>>> from luxonis_train.nodes import GhostFaceNetHead
>>> head = GhostFaceNetHead(
...     embedding_size=16,
...     input_shapes=[{"features": [Size([2, 8, 4, 4])]}],
...     original_in_shape=Size([3, 100, 100]),
... )
>>> packet = head.run([{"features": [torch.zeros(2, 8, 4, 4)]}])
>>> packet["embeddings"].shape
torch.Size([2, 16])
```

Parameters

 * `x` (`Tensor`): The last feature map of the backbone, of shape `[B, C, ceil(H / 32), ceil(W / 32)]`. `H` and `W` come from
   `original_in_shape`.

Returns

 * `Tensor`: The embeddings of shape `[B, embedding_size]`.
   [BaseNode.run](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
   puts them under the `"embeddings"` key.

##### initialize_weights

```python
def initialize_weights(method: str | None = None):
```

Initialize the convolutions and the 2D batch norm layers.

The method first calls
[BaseNode.initialize_weights](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md)
with `method`. Then it draws the weights of every `torch.nn.Conv2d` and `torch.nn.Linear` from a normal distribution with the mean
`0` and this standard deviation:

σ = √((2)/(nin(1 + a2)))

nin is the fan-in of the layer, and a is `0.25`. This is the Kaiming normal initialization for a leaky ReLU with the slope `0.25`.
The biases do not change.

Every `torch.nn.BatchNorm2d` then gets `momentum=0.9` and `eps=1e-5`. The 1D batch norm keeps its defaults. PyTorch uses
`momentum` as the weight of the new batch in the running statistics. With `0.9`, these statistics thus follow the last batches
closely.

> **Example**
> The node calls the method after construction:

```pycon
>>> from torch import Size
>>> from luxonis_train.nodes import GhostFaceNetHead
>>> head = GhostFaceNetHead(
...     input_shapes=[{"features": [Size([2, 8, 4, 4])]}],
...     original_in_shape=Size([3, 112, 112]),
...     weights="yolo",
... )
>>> batch_norm = head.head[0].bn
>>> batch_norm.momentum, batch_norm.eps
(0.9, 1e-05)
```

Parameters

 * `method` (`str | None`): The method for
   [BaseNode.initialize_weights](https://docs.luxonis.com/software-v3/ai-inference/model-source/training/luxonis-train/luxonis-train-api-reference/nodes/base_node.md).
   The value has no effect on this head. The head has no activation that `"yolo"` changes, and the method replaces the batch norm
   values of `"yolo"`.

#### Attributes

##### cross_batch_memory_size

##### embedding_size

##### head

##### 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_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.
