# dnn


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

## Setup

## Utils

------------------------------------------------------------------------

<a href="https://github.com/sky1ove/kmodel/blob/main/kmodel/dnn.py#L25"
target="_blank" style="float:right; font-size:smaller">source</a>

### seed_everything

``` python

def seed_everything(
    seed:int=123
)->None:

```

*Seed Python, NumPy, and PyTorch for reproducible experiments.*

``` python
seed_everything()
```

``` python
def_device
```

    'mps'

## Example Data

``` python
import seaborn as sns
from sklearn.model_selection import StratifiedKFold
```

``` python
seed_everything(123)
df = sns.load_dataset("penguins").dropna(
    subset=["bill_length_mm", "bill_depth_mm", "flipper_length_mm", "body_mass_g", "species"]
).reset_index(drop=True)
feat_col = ["bill_length_mm", "bill_depth_mm", "flipper_length_mm", "body_mass_g"]
target_df = pd.get_dummies(df["species"], prefix="species", dtype=float)
target_col = target_df.columns.tolist()
df[target_col] = target_df
n_feature = len(feat_col)
n_target = len(target_col)
n_aa = len(target_col)
skf = StratifiedKFold(n_splits=3, shuffle=True, random_state=123)
splits = list(skf.split(df.index, df["species"]))
split0 = splits[0]
df.shape
```

    (342, 10)

``` python
df[feat_col + ["species"] + target_col].head()
```

<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }
&#10;    .dataframe tbody tr th {
        vertical-align: top;
    }
&#10;    .dataframe thead th {
        text-align: right;
    }
</style>

<table class="dataframe" data-quarto-postprocess="true" data-border="1">
<thead>
<tr style="text-align: right;">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">bill_length_mm</th>
<th data-quarto-table-cell-role="th">bill_depth_mm</th>
<th data-quarto-table-cell-role="th">flipper_length_mm</th>
<th data-quarto-table-cell-role="th">body_mass_g</th>
<th data-quarto-table-cell-role="th">species</th>
<th data-quarto-table-cell-role="th">species_Adelie</th>
<th data-quarto-table-cell-role="th">species_Chinstrap</th>
<th data-quarto-table-cell-role="th">species_Gentoo</th>
</tr>
</thead>
<tbody>
<tr>
<td data-quarto-table-cell-role="th">0</td>
<td>39.1</td>
<td>18.7</td>
<td>181.0</td>
<td>3750.0</td>
<td>Adelie</td>
<td>1.0</td>
<td>0.0</td>
<td>0.0</td>
</tr>
<tr>
<td data-quarto-table-cell-role="th">1</td>
<td>39.5</td>
<td>17.4</td>
<td>186.0</td>
<td>3800.0</td>
<td>Adelie</td>
<td>1.0</td>
<td>0.0</td>
<td>0.0</td>
</tr>
<tr>
<td data-quarto-table-cell-role="th">2</td>
<td>40.3</td>
<td>18.0</td>
<td>195.0</td>
<td>3250.0</td>
<td>Adelie</td>
<td>1.0</td>
<td>0.0</td>
<td>0.0</td>
</tr>
<tr>
<td data-quarto-table-cell-role="th">3</td>
<td>36.7</td>
<td>19.3</td>
<td>193.0</td>
<td>3450.0</td>
<td>Adelie</td>
<td>1.0</td>
<td>0.0</td>
<td>0.0</td>
</tr>
<tr>
<td data-quarto-table-cell-role="th">4</td>
<td>39.3</td>
<td>20.6</td>
<td>190.0</td>
<td>3650.0</td>
<td>Adelie</td>
<td>1.0</td>
<td>0.0</td>
<td>0.0</td>
</tr>
</tbody>
</table>

</div>

## Dataset

------------------------------------------------------------------------

<a href="https://github.com/sky1ove/kmodel/blob/main/kmodel/dnn.py#L40"
target="_blank" style="float:right; font-size:smaller">source</a>

### GeneralDataset

``` python

def GeneralDataset(
    df:DataFrame, feat_col, target_col:NoneType=None, A:int=23, dtype:type=float32
)->None:

```

*An abstract class representing a :class:`Dataset`.*

All datasets that represent a map from keys to data samples should
subclass it. All subclasses should overwrite :meth:`__getitem__`,
supporting fetching a data sample for a given key. Subclasses could also
optionally overwrite :meth:`__len__`, which is expected to return the
size of the dataset by many :class:`~torch.utils.data.Sampler`
implementations and the default options of
:class:`~torch.utils.data.DataLoader`. Subclasses could also optionally
implement :meth:`__getitems__`, for speedup batched samples loading.
This method accepts list of indices of samples of batch and returns list
of samples.

.. note:: :class:`~torch.utils.data.DataLoader` by default constructs an
index sampler that yields integral indices. To make it work with a
map-style dataset with non-integral indices/keys, a custom sampler must
be provided.

``` python
ds = GeneralDataset(df, feat_col, target_col, A=n_aa)
xb, yb = next(iter(DataLoader(ds, batch_size=8, shuffle=True)))
len(ds), xb.shape, yb.shape
```

    (342, torch.Size([8, 4]), torch.Size([8, 3, 1]))

## Models

### MLP

------------------------------------------------------------------------

<a href="https://github.com/sky1ove/kmodel/blob/main/kmodel/dnn.py#L74"
target="_blank" style="float:right; font-size:smaller">source</a>

### MLP

``` python

def MLP(
    num_features:int, num_targets:int, hidden_units:list=[512, 218], dp:float=0.2
):

```

*Feed-forward model for tabular inputs.*

``` python
mlp = MLP(n_feature, n_target)
mlp(xb).shape
```

    torch.Size([8, 3])

### CNN1D

------------------------------------------------------------------------

<a href="https://github.com/sky1ove/kmodel/blob/main/kmodel/dnn.py#L98"
target="_blank" style="float:right; font-size:smaller">source</a>

### lin_wn

``` python

def lin_wn(
    ni, nf, dp:float=0.1, act:type=SiLU
):

```

*Weight-normalized linear block.*

``` python
lin_wn(10, 3)
```

    Sequential(
      (0): BatchNorm1d(10, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (1): Dropout(p=0.1, inplace=False)
      (2): ParametrizedLinear(
        in_features=10, out_features=3, bias=True
        (parametrizations): ModuleDict(
          (weight): ParametrizationList(
            (0): _WeightNorm()
          )
        )
      )
      (3): SiLU()
    )

------------------------------------------------------------------------

<a href="https://github.com/sky1ove/kmodel/blob/main/kmodel/dnn.py#L110"
target="_blank" style="float:right; font-size:smaller">source</a>

### conv_wn

``` python

def conv_wn(
    ni, nf, ks:int=3, stride:int=1, padding:int=1, dp:float=0.1, act:type=ReLU
):

```

*Weight-normalized convolution block.*

------------------------------------------------------------------------

<a href="https://github.com/sky1ove/kmodel/blob/main/kmodel/dnn.py#L122"
target="_blank" style="float:right; font-size:smaller">source</a>

### CNN1D

``` python

def CNN1D(
    ni, nf, amp_scale:int=16
):

```

*Base class for all neural network modules.*

Your models should also subclass this class.

Modules can also contain other Modules, allowing them to be nested in a
tree structure. You can assign the submodules as regular attributes::

    import torch.nn as nn
    import torch.nn.functional as F

    class Model(nn.Module):
        def __init__(self) -> None:
            super().__init__()
            self.conv1 = nn.Conv2d(1, 20, 5)
            self.conv2 = nn.Conv2d(20, 20, 5)

        def forward(self, x):
            x = F.relu(self.conv1(x))
            return F.relu(self.conv2(x))

Submodules assigned in this way will be registered, and will also have
their parameters converted when you call :meth:`to`, etc.

.. note:: As per the example above, an `__init__()` call to the parent
class must be made before assignment on the child.

:ivar training: Boolean represents whether this module is in training or
evaluation mode. :vartype training: bool

------------------------------------------------------------------------

<a href="https://github.com/sky1ove/kmodel/blob/main/kmodel/dnn.py#L157"
target="_blank" style="float:right; font-size:smaller">source</a>

### init_weights

``` python

def init_weights(
    m, leaky:float=0.0
):

```

*Initialize convolution layers with Kaiming normal weights.*

``` python
cnn = CNN1D(n_feature, n_target).apply(init_weights)
cnn(xb).shape
```

    torch.Size([8, 3])

## Wrapper

------------------------------------------------------------------------

<a href="https://github.com/sky1ove/kmodel/blob/main/kmodel/dnn.py#L163"
target="_blank" style="float:right; font-size:smaller">source</a>

### PSSM_model

``` python

def PSSM_model(
    n_features, n_targets, A:int=23, model:str='MLP'
):

```

*Base class for all neural network modules.*

Your models should also subclass this class.

Modules can also contain other Modules, allowing them to be nested in a
tree structure. You can assign the submodules as regular attributes::

    import torch.nn as nn
    import torch.nn.functional as F

    class Model(nn.Module):
        def __init__(self) -> None:
            super().__init__()
            self.conv1 = nn.Conv2d(1, 20, 5)
            self.conv2 = nn.Conv2d(20, 20, 5)

        def forward(self, x):
            x = F.relu(self.conv1(x))
            return F.relu(self.conv2(x))

Submodules assigned in this way will be registered, and will also have
their parameters converted when you call :meth:`to`, etc.

.. note:: As per the example above, an `__init__()` call to the parent
class must be made before assignment on the child.

:ivar training: Boolean represents whether this module is in training or
evaluation mode. :vartype training: bool

``` python
model = PSSM_model(n_feature, n_target, A=n_aa, model='MLP')
logits = model(xb)
logits.shape
```

    torch.Size([8, 3, 1])

## Loss

------------------------------------------------------------------------

<a href="https://github.com/sky1ove/kmodel/blob/main/kmodel/dnn.py#L185"
target="_blank" style="float:right; font-size:smaller">source</a>

### CE

``` python

def CE(
    logits:Tensor, target_probs:Tensor
):

```

*Cross-entropy with soft labels.*

``` python
CE(logits, yb)
```

    tensor(1.3051, grad_fn=<MeanBackward0>)

## Metrics

------------------------------------------------------------------------

<a href="https://github.com/sky1ove/kmodel/blob/main/kmodel/dnn.py#L192"
target="_blank" style="float:right; font-size:smaller">source</a>

### KLD

``` python

def KLD(
    logits:Tensor, target_probs:Tensor
):

```

*Average KL divergence across positions between target_probs and
softmax(logits).*

``` python
KLD(logits, yb)
```

    tensor(1.3051, grad_fn=<MeanBackward0>)

------------------------------------------------------------------------

<a href="https://github.com/sky1ove/kmodel/blob/main/kmodel/dnn.py#L200"
target="_blank" style="float:right; font-size:smaller">source</a>

### JSD

``` python

def JSD(
    logits:Tensor, target_probs:Tensor
):

```

*Average Jensen-Shannon divergence across positions between target_probs
and softmax(logits).*

``` python
JSD(logits, yb)
```

    tensor(0.3545, grad_fn=<MeanBackward0>)

## Trainer

------------------------------------------------------------------------

<a href="https://github.com/sky1ove/kmodel/blob/main/kmodel/dnn.py#L213"
target="_blank" style="float:right; font-size:smaller">source</a>

### train_dl

``` python

def train_dl(
    df:DataFrame, feat_col, target_col, split, model_func, A:int=23, n_epoch:int=4, bs:int=32, lr:float=0.01,
    loss:function=CE, save:NoneType=None, sampler:NoneType=None, lr_find:bool=False
):

```

*Train a deep learning model with the fastai learner stack.*

``` python
get_mlp = lambda: PSSM_model(n_feature, n_target, A=n_aa, model='MLP')
target, pred = train_dl(
    df,
    feat_col,
    target_col,
    split0,
    model_func=get_mlp,
    A=n_aa,
    n_epoch=1,
    bs=16,
    lr=3e-3,
    save='model',
)
pred.head()
```

    lr in training is 0.003

<style>
    progress { appearance: none; border: none; border-radius: 4px; width: 300px;
        height: 20px; vertical-align: middle; background: #e0e0e0; }
&#10;    progress::-webkit-progress-bar { background: #e0e0e0; border-radius: 4px; }
    progress::-webkit-progress-value { background: #2196F3; border-radius: 4px; }
    progress::-moz-progress-bar { background: #2196F3; border-radius: 4px; }
&#10;    progress:not([value]) {
        background: repeating-linear-gradient(45deg, #7e7e7e, #7e7e7e 10px, #5c5c5c 10px, #5c5c5c 20px); }
&#10;    progress.progress-bar-interrupted::-webkit-progress-value { background: #F44336; }
    progress.progress-bar-interrupted::-moz-progress-value { background: #F44336; }
    progress.progress-bar-interrupted::-webkit-progress-bar { background: #F44336; }
    progress.progress-bar-interrupted::-moz-progress-bar { background: #F44336; }
    progress.progress-bar-interrupted { background: #F44336; }    
&#10;    table.fastprogress { border-collapse: collapse; margin: 1em 0; font-size: 0.9em; }
    table.fastprogress th, table.fastprogress td { padding: 8px 12px; border: 1px solid #ddd; text-align: left; }
    table.fastprogress thead tr { background: #f8f9fa; font-weight: bold; }
    table.fastprogress tbody tr:nth-of-type(even) { background: #f8f9fa; }
</style>

``` html
<div>
  <table class="fastprogress">
    <thead>
      <tr>
        <th>epoch</th>
        <th>train_loss</th>
        <th>valid_loss</th>
        <th>KLD</th>
        <th>JSD</th>
        <th>time</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>0</td>
        <td>0.740750</td>
        <td>3.037915</td>
        <td>3.037915</td>
        <td>0.376177</td>
        <td>00:00</td>
      </tr>
    </tbody>
  </table>
</div>
```

<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }
&#10;    .dataframe tbody tr th {
        vertical-align: top;
    }
&#10;    .dataframe thead th {
        text-align: right;
    }
</style>

<table class="dataframe" data-quarto-postprocess="true" data-border="1">
<thead>
<tr style="text-align: right;">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">species_Adelie</th>
<th data-quarto-table-cell-role="th">species_Chinstrap</th>
<th data-quarto-table-cell-role="th">species_Gentoo</th>
</tr>
</thead>
<tbody>
<tr>
<td data-quarto-table-cell-role="th">0</td>
<td>0.009204</td>
<td>0.009344</td>
<td>0.981452</td>
</tr>
<tr>
<td data-quarto-table-cell-role="th">3</td>
<td>0.063467</td>
<td>0.055438</td>
<td>0.881095</td>
</tr>
<tr>
<td data-quarto-table-cell-role="th">9</td>
<td>0.182922</td>
<td>0.156108</td>
<td>0.660971</td>
</tr>
<tr>
<td data-quarto-table-cell-role="th">11</td>
<td>0.294663</td>
<td>0.286624</td>
<td>0.418712</td>
</tr>
<tr>
<td data-quarto-table-cell-role="th">14</td>
<td>0.011959</td>
<td>0.011384</td>
<td>0.976657</td>
</tr>
</tbody>
</table>

</div>

## Predict

------------------------------------------------------------------------

<a href="https://github.com/sky1ove/kmodel/blob/main/kmodel/dnn.py#L261"
target="_blank" style="float:right; font-size:smaller">source</a>

### predict_dl

``` python

def predict_dl(
    df, feat_col, target_col, model_func, model_pth, A:int=23, bs:int=512
):

```

*Predict a dataframe given a deep learning model saved by fastai.*

``` python
test_pred = predict_dl(
    df.iloc[split0[1]].copy(),
    feat_col,
    target_col,
    model_func=get_mlp,
    model_pth='model',
    A=n_aa,
)
test_pred
```

<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }
&#10;    .dataframe tbody tr th {
        vertical-align: top;
    }
&#10;    .dataframe thead th {
        text-align: right;
    }
</style>

<table class="dataframe" data-quarto-postprocess="true" data-border="1">
<thead>
<tr style="text-align: right;">
<th data-quarto-table-cell-role="th"></th>
<th data-quarto-table-cell-role="th">species_Adelie</th>
<th data-quarto-table-cell-role="th">species_Chinstrap</th>
<th data-quarto-table-cell-role="th">species_Gentoo</th>
</tr>
</thead>
<tbody>
<tr>
<td data-quarto-table-cell-role="th">0</td>
<td>9.204363e-03</td>
<td>9.344031e-03</td>
<td>0.981452</td>
</tr>
<tr>
<td data-quarto-table-cell-role="th">3</td>
<td>6.346702e-02</td>
<td>5.543802e-02</td>
<td>0.881095</td>
</tr>
<tr>
<td data-quarto-table-cell-role="th">9</td>
<td>1.829216e-01</td>
<td>1.561077e-01</td>
<td>0.660971</td>
</tr>
<tr>
<td data-quarto-table-cell-role="th">11</td>
<td>2.946635e-01</td>
<td>2.866240e-01</td>
<td>0.418712</td>
</tr>
<tr>
<td data-quarto-table-cell-role="th">14</td>
<td>1.195943e-02</td>
<td>1.138383e-02</td>
<td>0.976657</td>
</tr>
<tr>
<td data-quarto-table-cell-role="th">...</td>
<td>...</td>
<td>...</td>
<td>...</td>
</tr>
<tr>
<td data-quarto-table-cell-role="th">328</td>
<td>5.574878e-09</td>
<td>1.360372e-08</td>
<td>1.000000</td>
</tr>
<tr>
<td data-quarto-table-cell-role="th">334</td>
<td>2.227252e-10</td>
<td>7.630787e-10</td>
<td>1.000000</td>
</tr>
<tr>
<td data-quarto-table-cell-role="th">335</td>
<td>5.731530e-07</td>
<td>1.071595e-06</td>
<td>0.999998</td>
</tr>
<tr>
<td data-quarto-table-cell-role="th">339</td>
<td>5.872652e-10</td>
<td>1.706496e-09</td>
<td>1.000000</td>
</tr>
<tr>
<td data-quarto-table-cell-role="th">340</td>
<td>5.236147e-08</td>
<td>1.102807e-07</td>
<td>1.000000</td>
</tr>
</tbody>
</table>

<p>114 rows × 3 columns</p>
</div>

## CV train

------------------------------------------------------------------------

<a href="https://github.com/sky1ove/kmodel/blob/main/kmodel/dnn.py#L283"
target="_blank" style="float:right; font-size:smaller">source</a>

### train_dl_cv

``` python

def train_dl_cv(
    df, feat_col, target_col, splits, model_func, A:int=23, save:str | None=None, kwargs:VAR_KEYWORD
):

```

*Cross-validation training loop for deep learning models.*

``` python
oof = train_dl_cv(
    df,
    feat_col,
    target_col,
    splits=splits,
    model_func=get_mlp,
    A=n_aa,
    n_epoch=1,
    bs=16,
    lr=3e-3,
)
oof.nfold.value_counts()
```

    ------fold0------
    lr in training is 0.003

``` html
<div>
  <table class="fastprogress">
    <thead>
      <tr>
        <th>epoch</th>
        <th>train_loss</th>
        <th>valid_loss</th>
        <th>KLD</th>
        <th>JSD</th>
        <th>time</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>0</td>
        <td>0.713906</td>
        <td>2.601878</td>
        <td>2.601878</td>
        <td>0.355676</td>
        <td>00:00</td>
      </tr>
    </tbody>
  </table>
</div>
```

    ------fold1------
    lr in training is 0.003

``` html
<div>
  <table class="fastprogress">
    <thead>
      <tr>
        <th>epoch</th>
        <th>train_loss</th>
        <th>valid_loss</th>
        <th>KLD</th>
        <th>JSD</th>
        <th>time</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>0</td>
        <td>0.699992</td>
        <td>2.666008</td>
        <td>2.666008</td>
        <td>0.354615</td>
        <td>00:00</td>
      </tr>
    </tbody>
  </table>
</div>
```

    ------fold2------
    lr in training is 0.003

``` html
<div>
  <table class="fastprogress">
    <thead>
      <tr>
        <th>epoch</th>
        <th>train_loss</th>
        <th>valid_loss</th>
        <th>KLD</th>
        <th>JSD</th>
        <th>time</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>0</td>
        <td>0.633100</td>
        <td>2.994696</td>
        <td>2.994696</td>
        <td>0.354643</td>
        <td>00:00</td>
      </tr>
    </tbody>
  </table>
</div>
```

    nfold
    0    114
    1    114
    2    114
    Name: count, dtype: int64
