# How to Create Your Own Model
## Pipeline
![Pipeline](../assets/pipeline.png)

## A new model
If you want to design a new model, you need to write a class inherited from `BaseModel`, e.g, NewModel in newmodel.py:
```python
from ..base_model import BaseModel

class NewModel(BaseModel):
    def __init__(self, cfgs, is_training):
        super().__init__(cfgs, is_training)

    def build_network(self, model_cfg):
        self.encoder = ...

    def forward(self, inputs):
        ipts, labs, typs, viws, seqL = inputs
        sils = ipts[0]
        if len(sils.size()) == 4:
            sils = sils.unsqueeze(2)
        del ipts
        n, s, c, h, w = sils.size()

        embed_1, logits, embed = self.encoder(sils)

        return {
            'training_feat': {
                'triplet': {'embeddings': embed_1, 'labels': labs},
                'softmax': {'logits': logits, 'labels': labs}
            },
            'visual_summary': {
                'image/sils': sils.view(n*s, 1, h, w)
            },
            'inference_feat': {
                'embeddings': embed
            }
        }

```
 In your model class, at least you need to implement `build_network()` and `forward()` functions. The first is used to build the netwroks, and it does not need `return value`. Another is used to calculate the features, the `return value` is fixed in dictionary format

> `training_feat` is for the loss computing, and it must be a `dict` object. 
> 
> `visual_summary` is for visualization, and it must be a `dict` object. 
> 
> `inference_feat` is for the inference, and it must be a `dict` object. 
> 
> `triplet` and `softmax` are the prefixes (or names) of the loss function.
> 
> `embeddings`, `logits` and `labels` are the input arguments of the loss function.

More information should be seen in [base_model.py](../opengait/modeling/base_model.py) and [loss_aggregator.py](../opengait/modeling/loss_aggregator.py).

After finishing the model file, you have two steps left to do:

**Step 1**: Put your newmodel.py under `opengait/modeling/models`.

**Step 2**: Specify the model name in a yaml file:
```yaml
model_cfg:
  model: NewModel
  param1: ...
  param2: ...
  param3: ...
```


## A new loss
If you want to write a new loss, you need to write a class inherited from `opengait/modeling/losses`, like this
```python
from .base import BaseLoss

class NewLoss(BaseLoss):
    def __init__(self, *args, **kwargs):
        super(NewLoss, self).__init__(*args, **kargs)

    @gather_and_scale_wrapper
    def forward(self, embeddings, labels):
        pass
```
Remember to use `gather_and_scale_wrapper` to wrap your forward function if your loss is computed by pairs like `triplet`. By this, we gather all features to one GPU card and scale the loss by the number of GPUs.

Then, put your loss in `opengait/modeling/losses` so that you can use it in config file. 

Moreover, refer to [loss_aggregator.py](../opengait/modeling/loss_aggregator.py) to explore how does your defined loss work in the model.
