File size: 2,400 Bytes
54259e7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import torch
from torch import nn
from typing import Optional, Tuple

try:
    from transformers import PreTrainedModel, PretrainedConfig
except Exception as exc:  # pragma: no cover
    raise RuntimeError("transformers must be installed to use this model") from exc


class LSTMConfig(PretrainedConfig):
    model_type = "lstm_timeseries"

    def __init__(
        self,
        input_size: int = 1,
        hidden_size: int = 128,
        num_layers: int = 2,
        dropout: float = 0.1,
        len_seq: int = 180,
        len_pred: int = 12,
        **kwargs,
    ) -> None:
        super().__init__(**kwargs)
        self.input_size = input_size
        self.hidden_size = hidden_size
        self.num_layers = num_layers
        self.dropout = dropout
        self.len_seq = len_seq
        self.len_pred = len_pred


class _SimpleLSTM(nn.Module):
    def __init__(self, config: LSTMConfig) -> None:
        super().__init__()
        self.config = config
        self.lstm = nn.LSTM(
            input_size=config.input_size,
            hidden_size=config.hidden_size,
            num_layers=config.num_layers,
            batch_first=True,
            dropout=config.dropout,
        )
        self.projection = nn.Linear(config.hidden_size, config.len_pred)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        # x: (batch, len_seq, input_size)
        lstm_out, _ = self.lstm(x)
        last_hidden = lstm_out[:, -1, :]
        pred = self.projection(last_hidden)
        return pred


class LSTMForTimeSeries(PreTrainedModel):
    UPPER = 402
    LOWER = 38
    SCALE_1 = 5
    SCALE_2 = 2
    config_class = LSTMConfig

    def __init__(self, config: LSTMConfig) -> None:
        super().__init__(config)
        self.model = _SimpleLSTM(config)
        self.model.eval()

    def normalize_glucose(self, glucose):
        return (glucose - self.LOWER) / (self.UPPER - self.LOWER) * (self.SCALE_1 * self.SCALE_2) - self.SCALE_1

    def unnormalize_glucose(self, glucose):
        return (glucose + self.SCALE_1) / (self.SCALE_1 * self.SCALE_2) * (self.UPPER - self.LOWER) + self.LOWER

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        x = torch.tensor(x).reshape(-1, self.config.len_seq, 1).float()
        x = self.normalize_glucose(x)
        out = self.model(x)
        unnormalized_out = self.unnormalize_glucose(out)
        return unnormalized_out