diff --git a/docs/.nojekyll b/docs/.nojekyll deleted file mode 100644 index e69de29..0000000 diff --git a/docs/_images/HI_deviation.png b/docs/_images/HI_deviation.png deleted file mode 100644 index aed36e9..0000000 Binary files a/docs/_images/HI_deviation.png and /dev/null differ diff --git a/docs/_modules/ice/anomaly_detection/datasets.html b/docs/_modules/ice/anomaly_detection/datasets.html index da93e55..b6df286 100644 --- a/docs/_modules/ice/anomaly_detection/datasets.html +++ b/docs/_modules/ice/anomaly_detection/datasets.html @@ -414,6 +414,30 @@

Source code for ice.anomaly_detection.datasets

+ + +
[docs]class AnomalyDetectionRiethTEP(BaseDataset): + """ + Dataset of Tennessee Eastman Process dataset + Rieth, C. A., Amsel, B. D., Tran, R., & Cook, M. B. (2017). + Additional Tennessee Eastman Process Simulation Data for + Anomaly Detection Evaluation (Version V1) [Computer software]. + Harvard Dataverse. + https://doi.org/10.7910/DVN/6C3JR1. + """ + def __init__(self, num_chunks=None, force_download=False): + self.df = None + self.test_mask = None + self.name = None + self.public_link = None + self.set_name_public_link() + self._load(num_chunks, force_download) + self.target[self.target != 0] = 1 + self.train_mask[self.target != 0] = False + +
diff --git a/docs/_modules/ice/anomaly_detection/metrics.html b/docs/_modules/ice/anomaly_detection/metrics.html index ac961de..1f94cf9 100644 --- a/docs/_modules/ice/anomaly_detection/metrics.html +++ b/docs/_modules/ice/anomaly_detection/metrics.html @@ -366,19 +366,56 @@

Source code for ice.anomaly_detection.metrics

-
[docs]def accuracy(pred: list, target: list) -> float: +import numpy as np +from sklearn.metrics import confusion_matrix + + +
[docs]def accuracy(pred: np.ndarray, target: np.ndarray) -> float: """ Accuracy of the classification is the number of true positives divided by the number of examples. Args: - pred (list): predictions. - target (list): target values. + pred (np.ndarray): predictions. + target (np.ndarray): target values. Returns: - float: accuracy + float: accuracy. """ return sum(pred == target) / len(pred)
+ + +
[docs]def true_positive_rate(pred: np.ndarray, target: np.ndarray) -> np.ndarray[float]: + """ + True Positive Rate is the number of detected faults i divided by the + number of faults i. + + Args: + pred (np.ndarray): predictions. + target (np.ndarray): target values. + + Returns: + list: list of float values with true positive rate for each fault. + """ + cm = confusion_matrix(target, pred, labels=np.arange(target.max() + 1)) + correct = cm[1:, 1:].diagonal() + return list(correct / cm[1:].sum(axis=1))
+ + +
[docs]def false_positive_rate(pred: np.ndarray, target: np.ndarray) -> np.ndarray[float]: + """ + False Positive Rate, aka False Alarm Rate is the number of false alarms i + divided by the number of normal samples. + + Args: + pred (np.ndarray): predictions. + target (np.ndarray): target values. + + Returns: + list: list of float values with true positive rate for each fault. + """ + cm = confusion_matrix(target, pred, labels=np.arange(target.max() + 1)) + return list(cm[0, 1:] / cm[0].sum())
diff --git a/docs/_modules/ice/anomaly_detection/models/autoencoder.html b/docs/_modules/ice/anomaly_detection/models/autoencoder.html index 84bb12e..34a334d 100644 --- a/docs/_modules/ice/anomaly_detection/models/autoencoder.html +++ b/docs/_modules/ice/anomaly_detection/models/autoencoder.html @@ -366,8 +366,7 @@

Source code for ice.anomaly_detection.models.autoencoder

-from pandas import DataFrame
-from sklearn.preprocessing import StandardScaler
+import pandas as pd
 from torch import nn
 
 from ice.anomaly_detection.models.base import BaseAnomalyDetection
@@ -376,48 +375,41 @@ 

Source code for ice.anomaly_detection.models.autoencoder

[docs]class MLP(nn.Module): def __init__( self, - num_sensors: int, + input_dim: int, window_size: int, - num_layers: int, hidden_dims: list, - type: str + decoder: bool = False, ): super().__init__() - self.num_sensors = num_sensors + self.input_dim = input_dim self.window_size = window_size - self.hidden_dims = [num_sensors * window_size] - self.type = type - if hidden_dims is not None and self.type == 'encoder': - self.hidden_dims = self.hidden_dims + hidden_dims - elif hidden_dims is not None and self.type == 'decoder': + self.hidden_dims = [input_dim * window_size] + self.decoder = decoder + if self.decoder: self.hidden_dims = hidden_dims + self.hidden_dims else: - for i in range(num_layers): - dim = self.hidden_dims[i] // 2 - self.hidden_dims.append(dim) - if self.type == 'decoder': - self.hidden_dims.reverse() + self.hidden_dims = self.hidden_dims + hidden_dims self.mlp = nn.Sequential(nn.Flatten()) - for i in range(num_layers): + for i in range(len(hidden_dims)): self.mlp.append(nn.Linear( self.hidden_dims[i], self.hidden_dims[i + 1]) ) - if self.type == 'decoder' and i + 1 == num_layers: + if self.decoder and i + 1 == len(hidden_dims): break self.mlp.append(nn.ReLU())
[docs] def forward(self, x): output = self.mlp(x) - if self.type == 'decoder': - return output.view(-1, self.window_size, self.num_sensors) + if self.decoder: + return output.view(-1, self.window_size, self.input_dim) return output
[docs]class AutoEncoderMLP(BaseAnomalyDetection): """ - Autoencoder (AE) consists of encoder and decoder parts. Each + MLP autoencoder consists of MLP encoder and MLP decoder parts. Each sample is reshaped to a vector (B, L, C) -> (B, L * C) for calculations and to a vector (B, L * C) -> (B, L, C) for the output. Where B is the batch size, L is the sequence length, C is the number of sensors. @@ -425,18 +417,24 @@

Source code for ice.anomaly_detection.models.autoencoder

def __init__( self, window_size: int, + stride: int = 1, batch_size: int = 128, lr: float = 0.001, num_epochs: int = 10, device: str = 'cpu', verbose: bool = False, name: str = 'ae_anomaly_detection', - threshold: float = 0.95, - hidden_dims: list = [256, 128, 64], + random_seed: int = 42, + val_ratio: float = 0.15, + save_checkpoints: bool = False, + threshold_level: float = 0.95, + hidden_dims: list = [256, 128, 64] ): """ Args: window_size (int): The window size to train the model. + stride (int): The time interval between first points of consecutive + sliding windows in training. batch_size (int): The batch size to train the model. lr (float): The larning rate to train the model. num_epochs (float): The number of epochs to train the model. @@ -444,20 +442,19 @@

Source code for ice.anomaly_detection.models.autoencoder

`cuda` are possible. verbose (bool): If true, show the progress bar in training. name (str): The name of the model for artifact storing. - threshold (float): The boundary for anomaly detection. + random_seed (int): Seed for random number generation to ensure reproducible results. + val_ratio (float): Proportion of the dataset used for validation, between 0 and 1. + save_checkpoints (bool): If true, store checkpoints. + threshold_level (float): Takes a value from 0 to 1. It specifies + the quantile in the distribution of errors on the training + dataset at which the threshold value is set. hidden_dims (list): Dimensions of hidden layers in encoder/decoder. """ super().__init__( - window_size, batch_size, lr, num_epochs, device, verbose, name, threshold + window_size, stride, batch_size, lr, num_epochs, device, verbose, name, random_seed, + val_ratio, save_checkpoints, threshold_level ) - - self.window_size = window_size - self.num_layers = len(hidden_dims) self.hidden_dims = hidden_dims - self.threshold = threshold - self.loss_fn = nn.MSELoss(reduction='mean') - self.preprocessing = True - self.scaler = StandardScaler() _param_conf_map = dict(BaseAnomalyDetection._param_conf_map, **{ @@ -465,24 +462,20 @@

Source code for ice.anomaly_detection.models.autoencoder

} ) - def _create_model(self, df: DataFrame): - num_sensors = df.shape[1] + def _create_model(self, input_dim: int, output_dim: int): self.model = nn.Sequential( MLP( - num_sensors, + input_dim, self.window_size, - self.num_layers, hidden_dims=self.hidden_dims, - type='encoder' ), MLP( - num_sensors, + input_dim, self.window_size, - self.num_layers, hidden_dims=self.hidden_dims[::-1], - type='decoder' + decoder=True ) - )
+ )
diff --git a/docs/_modules/ice/anomaly_detection/models/base.html b/docs/_modules/ice/anomaly_detection/models/base.html index 714b56e..71c0600 100644 --- a/docs/_modules/ice/anomaly_detection/models/base.html +++ b/docs/_modules/ice/anomaly_detection/models/base.html @@ -369,15 +369,16 @@

Source code for ice.anomaly_detection.models.base

from abc import ABC, abstractmethod import numpy as np import pandas as pd -from tqdm.auto import trange, tqdm - +from tqdm.auto import tqdm import torch -from torch.optim import Adam +import torch.nn as nn from torch.utils.data import DataLoader +from torch.optim import Adam +import optuna -from ice.anomaly_detection.utils import SlidingWindowDataset -from ice.base import BaseModel -from ice.anomaly_detection.metrics import accuracy +from ice.base import BaseModel, SlidingWindowDataset +from ice.anomaly_detection.metrics import ( + accuracy, true_positive_rate, false_positive_rate)
[docs]class BaseAnomalyDetection(BaseModel, ABC): @@ -387,17 +388,23 @@

Source code for ice.anomaly_detection.models.base

def __init__( self, window_size: int, + stride: int, batch_size: int, lr: float, num_epochs: int, device: str, verbose: bool, name: str, - threshold: float = 0.95 - ): + random_seed: int, + val_ratio: float, + save_checkpoints: bool, + threshold_level: float = 0.95 + ): """ Args: window_size (int): The window size to train the model. + stride (int): The time interval between first points of consecutive + sliding windows in training. batch_size (int): The batch size to train the model. lr (float): The learning rate to train the model. num_epochs (float): The number of epochs to train the model. @@ -405,105 +412,98 @@

Source code for ice.anomaly_detection.models.base

`cuda` are possible. verbose (bool): If true, show the progress bar in training. name (str): The name of the model for artifact storing. + random_seed (int): Seed for random number generation to ensure reproducible results. + val_ratio (float): Proportion of the dataset used for validation, between 0 and 1. + save_checkpoints (bool): If true, store checkpoints. + threshold_level (float): Takes a value from 0 to 1. It specifies + the quantile in the distribution of errors on the training + dataset at which the threshold value is set. """ - super().__init__(batch_size, lr, num_epochs, device, verbose, name) - self._cfg.path_set(["TASK"], "anomaly_detection") + super().__init__(window_size, stride, batch_size, lr, num_epochs, device, verbose, name, random_seed, val_ratio, save_checkpoints) + self.val_metrics = False + + self.threshold_level = threshold_level + self.threshold_value = None - self.window_size = window_size - self.loss_fn = None - self.preprocessing = False - self.scaler = None - self.threshold = None +
[docs] def fit(self, df: pd.DataFrame, target: pd.Series = None, + epochs: int = None, save_path: str = None, trial: optuna.Trial = None, + force_model_ctreation: bool = False): + """Fit (train) the model by a given dataset. + + Args: + df (pandas.DataFrame): A dataframe with sensor data. Index has + two columns: `run_id` and `sample`. All other columns a value of + sensors. + target (pandas.Series): A series with target values. Indes has two + columns: `run_id` and `sample`. It is omitted for anomaly + detection task. + epochs (int): The number of epochs for training step. If None, + self.num_epochs parameter is used. + save_path (str): Path to save checkpoints. If None, the path is + created automatically. + """ + if trial: + super().fit(df, target, epochs, save_path, trial=trial, force_model_ctreation=True) + else: + super().fit(df, target, epochs, save_path) + + error = [] + for sample, target in tqdm( + self.dataloader, desc='Steps ...', leave=False, disable=(not self.verbose) + ): + sample = sample.to(self.device) + with torch.no_grad(): + pred = self.model(sample) + error.append(self.loss_no_reduction(pred, sample).mean(dim=(1, 2))) + error = torch.concat(error) + self.threshold_value = torch.quantile(error, self.threshold_level).item() + if self.save_checkpoints: + self.save_checkpoint(save_path)
_param_conf_map = dict(BaseModel._param_conf_map, **{ - "window_size": ["MODEL", "WINDOW_SIZE"], - "threshold": ["MODEL", "THRESHOLD"] + "threshold_level": ["MODEL", "THRESHOLD_LEVEL"] } ) - -
[docs] def fit(self, df: pd.DataFrame): - """ Method fit for training anomaly detection models. + +
[docs] def load_checkpoint(self, checkpoint_path: str): + """Load checkpoint. Args: - df (pd.DataFrame): data without anomaly states + checkpoint_path (str): Path to load checkpoint. """ - assert len(df) >= self.window_size, "window size is larger than the length of df." - if self.preprocessing: - self.scaler.fit(df) - df.loc[:] = self.scaler.transform(df) - self._create_model(df) - self._train_nn(df)
- - def _fit(self, df: pd.DataFrame): - pass + super().load_checkpoint(checkpoint_path) + self.threshold_value = self._cfg['MODEL']['THRESHOLD_VALUE']
+ + def _prepare_for_training(self, input_dim: int, output_dim: int): + self.optimizer = Adam(self.model.parameters(), lr=self.lr) + self.loss_fn = nn.L1Loss() + self.loss_no_reduction = nn.L1Loss(reduction='none') def _predict(self, sample: torch.Tensor) -> torch.Tensor: input = sample.to(self.device) output = self.model(input) - return output.cpu() - - def _train_nn(self, df: pd.DataFrame): - self.model.train() - self.model.to(self.device) - self.optimizer = Adam(self.model.parameters(), lr=self.lr) - - dataset = SlidingWindowDataset(df, window_size=self.window_size) - self.dataloader = DataLoader(dataset, batch_size=self.batch_size, shuffle=True) - errors = [] - for e in trange(self.num_epochs, desc='Epochs ...', disable=(not self.verbose)): - for sample in tqdm(self.dataloader, desc='Steps ...', leave=False, disable=(not self.verbose)): - input = sample.to(self.device) - output = self.model(input) - loss = self.loss_fn(output, input) - self.optimizer.zero_grad() - loss.backward() - self.optimizer.step() - error = torch.sum(torch.abs(input - output), dim=(1, 2)) - errors = np.append(errors, error.detach().numpy()) - if self.verbose: - print(f'Epoch {e+1}, Loss: {loss.item():.4f}') - self.threshold_value = np.quantile(errors, self.threshold) - -
[docs] def evaluate(self, df: pd.DataFrame, target: pd.Series) -> dict: - """Evaluate the metrics: accuracy. - - Args: - df (pandas.DataFrame): A dataframe with sensor data. Index has - two columns: `run_id` and `sample`. All other columns a value of - sensors. - target (pandas.Series): A series with target values. Indes has two - columns: `run_id` and `sample`. + error = self.loss_no_reduction(output, input).mean(dim=(1, 2)) + return (error > self.threshold_value).float().cpu() + + def _validate_inputs(self, df: pd.DataFrame, target: pd.Series): + if target is not None: + assert df.shape[0] == target.shape[0], f"target is incompatible with df by the length: {df.shape[0]} and {target.shape[0]}." + assert np.all(df.index == target.index), "target's index and df's index are not the same." + assert df.index.names == (['run_id', 'sample']), "An index should contain columns `run_id` and `sample`." + assert len(df) >= self.window_size, "window size is larger than the length of df." - Returns: - dict: A dictionary with metrics where keys are names of metrics and - values are values of metrics. - """ - assert df.shape[0] == target.shape[0], f"target is incompatible with df by the length: {df.shape[0]} and {target.shape[0]}." - assert np.all(df.index == target.index), "target's index and df's index are not the same." - assert df.index.names == (['run_id', 'sample']), "An index should contain columns `run_id` and `sample`." - - if self.preprocessing: - df.loc[:] = self.scaler.transform(df) - dataset = SlidingWindowDataset(df, window_size=self.window_size, target=target) - self.dataloader = DataLoader(dataset, batch_size=self.batch_size, shuffle=True) - target, pred = [], [] - for sample, _target in tqdm( - self.dataloader, desc='Steps ...', leave=False, disable=(not self.verbose) - ): - input = sample.to(self.device) - target.append(_target) - with torch.no_grad(): - output = self.predict(input) - error = torch.sum(torch.abs(input - output), dim=(1, 2)) - pred.append((error > self.threshold_value).float()) - target = torch.concat(target).numpy() - pred = torch.concat(pred).numpy() + def _calculate_metrics(self, pred: torch.tensor, target: torch.tensor) -> dict: metrics = { - 'accuracy': accuracy(pred, target) + 'accuracy': accuracy(pred, target), + 'true_positive_rate': true_positive_rate(pred, target), + 'false_positive_rate': false_positive_rate(pred, target), } - self._store_atrifacts_inference(metrics) - return metrics
+ return metrics + + def _set_dims(self, df: pd.DataFrame, target: pd.Series): + self.input_dim = df.shape[1] + self.output_dim = 1
diff --git a/docs/_modules/ice/anomaly_detection/models/gnn.html b/docs/_modules/ice/anomaly_detection/models/gnn.html new file mode 100644 index 0000000..700432f --- /dev/null +++ b/docs/_modules/ice/anomaly_detection/models/gnn.html @@ -0,0 +1,607 @@ + + + + + + + + + + + ice.anomaly_detection.models.gnn — ICE documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +

Source code for ice.anomaly_detection.models.gnn

+import torch
+from torch import nn
+from torch.nn import functional as F
+from pandas import DataFrame, Series
+
+from ice.anomaly_detection.models.base import BaseAnomalyDetection
+
+
+class GCLayer(nn.Module):
+    def __init__(
+            self,
+            in_dim: int,
+            out_dim: int
+            ):
+        super().__init__()
+        self.dense = nn.Linear(in_dim, out_dim)
+    
+    def forward(self, adj, x):
+        adj = adj + torch.eye(adj.size(0)).to(x.device)
+        x = self.dense(x)
+        norm = adj.sum(1)**(-1/2)
+        x = norm[None, :] * adj * norm[:, None] @ x
+
+        return x
+
+
+class Directed_A(nn.Module):
+    def __init__(
+            self,
+            num_sensors: int,
+            window_size: int,
+            alpha: float,
+            k: int
+            ):
+        super().__init__()
+        self.alpha = alpha
+        self.k = k
+
+        self.e1 = nn.Embedding(num_sensors, window_size)
+        self.e2 = nn.Embedding(num_sensors, window_size)
+        self.l1 = nn.Linear(window_size,window_size)
+        self.l2 = nn.Linear(window_size,window_size)
+    
+    def forward(self, idx):
+        m1 = torch.tanh(self.alpha*self.l1(self.e1(idx)))
+        m2 = torch.tanh(self.alpha*self.l2(self.e2(idx)))
+        adj = F.relu(torch.tanh(self.alpha*torch.mm(m1, m2.transpose(1,0))))
+        
+        if self.k:
+            mask = torch.zeros(idx.size(0), idx.size(0)).to(idx.device)
+            mask.fill_(float('0'))
+            s1,t1 = (adj + torch.rand_like(adj)*0.01).topk(self.k,1)
+            mask.scatter_(1,t1,s1.fill_(1))
+            adj = adj*mask
+        
+        return adj
+
+
+class GNNEncoder(nn.Module):
+    def __init__(
+            self,
+            num_sensors: int,
+            window_size: int,
+            alpha: float,
+            k: int
+            ):
+        super().__init__()
+        self.idx = torch.arange(num_sensors)
+        self.gcl1 = GCLayer(window_size, window_size // 2)
+        self.gcl2 = GCLayer(window_size // 2, window_size // 8)
+        self.A = Directed_A(num_sensors, window_size, alpha, k)
+    
+    def forward(self, x):
+        x = torch.transpose(x, 1, 2)
+        adj = self.A(self.idx.to(x.device))
+        x = self.gcl1(adj, x).relu()
+        x = self.gcl2(adj, x).relu()
+        return x
+    
+
+class Decoder(nn.Module):
+    def __init__(
+            self,
+            num_sensors: int,
+            window_size: int
+            ):
+        super().__init__()
+        self.num_sensors = num_sensors
+        self.window_size = window_size
+        self.decoder = nn.Sequential(
+            nn.Linear(window_size // 8 * num_sensors, window_size // 2 * num_sensors),
+            nn.ReLU(),
+            nn.Linear(window_size // 2 * num_sensors, num_sensors * window_size)
+        )
+    
+    def forward(self, x):
+        x = torch.flatten(x,1)
+        x = self.decoder(x)
+
+        return x.view(-1, self.window_size, self.num_sensors)
+
+
+
[docs]class GSL_GNN(BaseAnomalyDetection): + """ + GNN autoencoder consists of encoder with graph convolutional layers + and MLP decoder parts. The graph describing the data is constructed + during the training process using trainable parameters. + """ + def __init__( + self, + window_size: int, + stride: int = 1, + batch_size: int = 128, + lr: float = 0.001, + num_epochs: int = 10, + device: str = 'cpu', + verbose: bool = False, + name: str = 'gnn_anomaly_detection', + random_seed: int = 42, + val_ratio: float = 0.15, + save_checkpoints: bool = False, + threshold_level: float = 0.95, + alpha: float = 0.2, + k: int = None + ): + """ + Args: + window_size (int): The window size to train the model. + stride (int): The time interval between first points of consecutive + sliding windows in training. + batch_size (int): The batch size to train the model. + lr (float): The larning rate to train the model. + num_epochs (float): The number of epochs to train the model. + device (str): The name of a device to train the model. `cpu` and + `cuda` are possible. + verbose (bool): If true, show the progress bar in training. + name (str): The name of the model for artifact storing. + random_seed (int): Seed for random number generation to ensure reproducible results. + val_ratio (float): Proportion of the dataset used for validation, between 0 and 1. + save_checkpoints (bool): If true, store checkpoints. + threshold_level (float): Takes a value from 0 to 1. It specifies + the quantile in the distribution of errors on the training + dataset at which the threshold value is set. + alpha (float): Saturation rate for adjacency matrix. + k (int): Limit on the number of edges in the adjacency matrix. + """ + super().__init__( + window_size, stride, batch_size, lr, num_epochs, device, verbose, name, random_seed, + val_ratio, save_checkpoints, threshold_level + ) + self.alpha = alpha + self.k = k + + _param_conf_map = dict(BaseAnomalyDetection._param_conf_map, + **{ + "alpha": ["MODEL", "ALPHA"] + } + ) + + def _create_model(self, input_dim: int, output_dim: int): + self.model = nn.Sequential( + GNNEncoder( + input_dim, + self.window_size, + self.alpha, + self.k + ), + Decoder(input_dim, self.window_size) + )
+
+ +
+ + + + + +
+ +
+
+
+ +
+ + + + +
+
+ +
+ +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/docs/_modules/ice/anomaly_detection/models/stgat.html b/docs/_modules/ice/anomaly_detection/models/stgat.html new file mode 100644 index 0000000..a6dacec --- /dev/null +++ b/docs/_modules/ice/anomaly_detection/models/stgat.html @@ -0,0 +1,733 @@ + + + + + + + + + + + ice.anomaly_detection.models.stgat — ICE documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +

Source code for ice.anomaly_detection.models.stgat

+import pandas as pd
+import torch
+import torch.nn as nn
+from torch.nn import functional as F
+from torch_geometric.nn import GCNConv, GATConv
+
+from ice.anomaly_detection.models.base import BaseAnomalyDetection
+
+
+"""
+The code of Stgat-Mad is taken from:
+https://github.com/wagner-d/TimeSeAD
+"""
+
+
+class InputLayer(nn.Module):
+    """1-D Convolution layer to extract high-level features of each time-series input
+    :param n_features: Number of input features/nodes
+    :param window_size: length of the input sequence
+    :param kernel_size: size of kernel to use in the convolution operation
+    """
+    def __init__(self, n_features, kernel_size=7):
+        super(InputLayer, self).__init__()
+        self.padding = nn.ConstantPad1d((kernel_size - 1) // 2, 0.0)
+        self.conv = nn.Conv1d(in_channels=n_features, out_channels=n_features, kernel_size=kernel_size)
+        self.relu = nn.ReLU()
+
+    def forward(self, x):
+        x = x.permute(0, 2, 1)
+        x = self.padding(x)
+        x = self.relu(self.conv(x))
+        return x.permute(0, 2, 1)  # Permute back
+
+
+class StgatBlock(nn.Module):
+    def __init__(self, n_features, window_size, dropout, embed_dim=None):
+        super(StgatBlock, self).__init__()
+        self.n_features = n_features
+        self.window_size = window_size
+        self.dropout = dropout
+        self.embed_dim = embed_dim if embed_dim is not None else n_features
+
+        self.embed_dim *= 2
+
+        self.feature_gat_layers = GATConv(window_size, window_size)
+        self.temporal_gat_layers = GATConv(n_features, n_features)
+
+        self.temporal_gcn_layers = GCNConv(n_features, n_features)
+
+    def forward(self, data, fc_edge_index, tc_edge_index):
+        # x shape (b, n, k): b - batch size, n - window size, k - number of features
+        x = data.clone().detach()
+        x = x.permute(0, 2, 1)
+        batch_num, node_num, all_feature = x.shape
+
+        x = x.reshape(-1, all_feature).contiguous()
+        f_out = self.feature_gat_layers(x, fc_edge_index)
+        f_out = F.relu(f_out)
+        f_out = f_out.view(batch_num, node_num, -1)
+        f_out = f_out.permute(0, 2, 1)
+        z = f_out.reshape(-1, node_num).contiguous()
+
+        t_out = self.temporal_gcn_layers(z, tc_edge_index)
+        t_out = F.relu(t_out)
+        t_out = t_out.view(batch_num, node_num, -1)
+
+        return t_out.permute(0, 2, 1)
+
+
+class BiLSTMLayer(nn.Module):
+    def __init__(self, in_dim, hid_dim, n_layers, dropout):
+        super(BiLSTMLayer, self).__init__()
+        self.hid_dim = hid_dim
+        self.n_layers = n_layers
+        self.dropout = 0.0 if n_layers == 1 else dropout
+        self.bilstm = nn.LSTM(in_dim, hid_dim, num_layers=n_layers, batch_first=True, dropout=self.dropout, bidirectional=True)
+
+    def forward(self, x):
+        out, h = self.bilstm(x)
+        out = out.permute(1,0,2)[-1, :, :] # Extracting from last layer
+        return out
+
+
+class BiLSTMDecoder(nn.Module):
+    def __init__(self, in_dim, hid_dim, n_layers, dropout):
+        super(BiLSTMDecoder, self).__init__()
+        self.in_dim = in_dim
+        self.dropout = 0.0 if n_layers == 1 else dropout
+        self.bilstm = nn.LSTM(in_dim, hid_dim, num_layers=n_layers, batch_first=True, dropout=self.dropout, bidirectional=True)
+
+    def forward(self, x):
+        decoder_out, _ = self.bilstm(x)
+        return decoder_out
+
+
+class ReconstructionModel(nn.Module):
+    def __init__(self, window_size, in_dim, hid_dim, out_dim, n_layers, dropout):
+        super(ReconstructionModel, self).__init__()
+        self.window_size = window_size
+        self.decoder = BiLSTMDecoder(in_dim, hid_dim, n_layers, dropout)
+        self.fc = nn.Linear(2 * hid_dim, out_dim)
+
+    def forward(self, x):
+        # x will be last hidden state of the GRU layer
+        h_end = x
+        h_end_rep = h_end.repeat_interleave(self.window_size, dim=1).view(x.size(0), self.window_size, -1)
+        decoder_out = self.decoder(h_end_rep)
+        out = self.fc(decoder_out)
+        return out
+
+
+def get_batch_edge_index(org_edge_index, batch_num, node_num):
+    # org_edge_index:(2, edge_num)
+    edge_index = org_edge_index.clone().detach()
+    edge_num = org_edge_index.shape[1]
+    batch_edge_index = edge_index.repeat(1,batch_num).contiguous()
+
+    for i in range(batch_num):
+        batch_edge_index[:, i*edge_num:(i+1)*edge_num] += i*node_num
+
+    return batch_edge_index.long()
+
+# graph is 'fully-connect'
+def get_fc_graph_struc(n_features):
+    edge_indices = torch.tensor([[i, j] for j in range(n_features) for i in range(n_features) if i != j])
+    return edge_indices.T.contiguous()
+
+
+def get_tc_graph_struc(temporal_len):
+    edge_indices = torch.tensor([[i, j] for j in range(temporal_len) for i in range(j)])
+    return edge_indices.T.contiguous()
+
+
+
[docs]class STGAT(nn.Module): + def __init__( + self, + n_features, + window_size, + embed_dim, + layer_numb, + lstm_n_layers, + lstm_hid_dim, + recon_n_layers, + recon_hid_dim, + dropout + ): + super(STGAT, self).__init__() + + layers1 = [] + layers2 = [] + layers3 = [] + + self.layer_numb = layer_numb + self.h_temp = [] + + self.input_1 = InputLayer(n_features, 1) + self.input_2 = InputLayer(n_features, 5) + self.input_3 = InputLayer(n_features, 7) + + for i in range(layer_numb): + layers1 += [StgatBlock(n_features, window_size, dropout, embed_dim)] + for i in range(layer_numb): + layers2 += [StgatBlock(n_features, window_size, dropout, embed_dim)] + for i in range(layer_numb): + layers3 += [StgatBlock(n_features, window_size, dropout, embed_dim)] + + self.stgat_1 = nn.Sequential(*layers1) + self.stgat_2 = nn.Sequential(*layers2) + self.stgat_3 = nn.Sequential(*layers3) + + self.bilstm = BiLSTMLayer(n_features * 3, lstm_hid_dim, lstm_n_layers, dropout) + self.recon_model = ReconstructionModel(window_size, 2 * lstm_hid_dim, recon_hid_dim, n_features, recon_n_layers, dropout) + + # Register as buffers so that tensors are moved to the correct device along with the rest of the model + self.register_buffer('fc_edge_index', get_fc_graph_struc(n_features), persistent=False) + self.register_buffer('tc_edge_index', get_tc_graph_struc(window_size), persistent=False) + +
[docs] def forward(self, x): + # x shape (b, n, k): b - batch size, n - window size, k - number of features + fc_edge_index_sets = get_batch_edge_index(self.fc_edge_index, x.shape[0], x.shape[2]) + tc_edge_index_sets = get_batch_edge_index(self.tc_edge_index, x.shape[0], x.shape[1]) + + x_1 = x + x_2 = self.input_2(x) + x_3 = self.input_3(x) + + for layer in range(self.layer_numb): + if layer==0: + h_cat_1 = x_1 + self.stgat_1[layer](x_1, fc_edge_index_sets, tc_edge_index_sets) + h_cat_2 = x_2 + self.stgat_2[layer](x_2, fc_edge_index_sets, tc_edge_index_sets) + h_cat_3 = x_3 + self.stgat_3[layer](x_3, fc_edge_index_sets, tc_edge_index_sets) + else: + h_cat_1 = h_cat_1 + self.stgat_1[layer](h_cat_1, fc_edge_index_sets, tc_edge_index_sets) + h_cat_2 = h_cat_2 + self.stgat_2[layer](h_cat_2, fc_edge_index_sets, tc_edge_index_sets) + h_cat_3 = h_cat_3 + self.stgat_3[layer](h_cat_3, fc_edge_index_sets, tc_edge_index_sets) + + h_cat = torch.cat([h_cat_1, h_cat_2, h_cat_3], dim=2) + + out_end = self.bilstm(h_cat) + h_end = out_end.view(x.shape[0], -1) # Hidden state for last timestamp + + recons = self.recon_model(h_end) + + return recons
+ + +class STGAT_MAD(BaseAnomalyDetection): + """ + Stgat-Mad was presented at ICASSP 2022: "Stgat-Mad : Spatial-Temporal Graph + Attention Network For Multivariate Time Series Anomaly Detection". + https://ieeexplore.ieee.org/abstract/document/9747274/ + """ + def __init__( + self, + window_size: int, + stride: int = 1, + batch_size: int = 128, + lr: float = 0.001, + num_epochs: int = 10, + device: str = 'cpu', + verbose: bool = False, + name: str = 'stgat_anomaly_detection', + random_seed: int = 42, + val_ratio: float = 0.15, + save_checkpoints: bool = False, + threshold_level: float = 0.95, + embed_dim: int = None, + layer_numb: int = 2, + lstm_n_layers: int = 1, + lstm_hid_dim: int = 150, + recon_n_layers: int = 1, + recon_hid_dim: int = 150, + dropout: float = 0.2 + ): + """ + Args: + window_size (int): The window size to train the model. + stride (int): The time interval between first points of consecutive + sliding windows in training. + batch_size (int): The batch size to train the model. + lr (float): The larning rate to train the model. + num_epochs (float): The number of epochs to train the model. + device (str): The name of a device to train the model. `cpu` and + `cuda` are possible. + verbose (bool): If true, show the progress bar in training. + name (str): The name of the model for artifact storing. + random_seed (int): Seed for random number generation to ensure reproducible results. + val_ratio (float): Proportion of the dataset used for validation, between 0 and 1. + save_checkpoints (bool): If true, store checkpoints. + threshold_level (float): Takes a value from 0 to 1. It specifies + the quantile in the distribution of errors on the training + dataset at which the threshold value is set. + embed_dim (int) : Embedding dimension. + layer_numb (int) : Number of layers. + lstm_n_layers (int) : Number of LSTM layers. + lstm_hid_dim (int) : Hidden dimension of LSTM layers. + recon_n_layers (int) : Number of reconstruction layers. + recon_hid_dim (int) : Hidden dimension of reconstruction layers. + dropout (float) : The rate of dropout. + """ + super().__init__( + window_size, stride, batch_size, lr, num_epochs, device, verbose, name, random_seed, + val_ratio, save_checkpoints, threshold_level + ) + self.embed_dim = embed_dim + self.layer_numb = layer_numb + self.lstm_n_layers = lstm_n_layers + self.lstm_hid_dim = lstm_hid_dim + self.recon_n_layers = recon_n_layers + self.recon_hid_dim = recon_hid_dim + self.dropout = dropout + + _param_conf_map = dict(BaseAnomalyDetection._param_conf_map, + **{ + "layer_numb": ["MODEL", "LAYER_NUMB"], + "lstm_n_layers": ["MODEL", "LSTM_N_LAYERS"], + "lstm_hid_dim": ["MODEL", "LSTM_HID_DIM"], + "recon_n_layers": ["MODEL", "RECON_N_LAYERS"], + "recon_hid_dim": ["MODEL", "RECON_HID_DIM"], + "dropout": ["MODEL", "DROPOUT"] + } + ) + + def _create_model(self, input_dim: int, output_dim: int): + self.model = STGAT( + n_features=input_dim, + window_size=self.window_size, + embed_dim=self.embed_dim, + layer_numb=self.layer_numb, + lstm_n_layers=self.lstm_n_layers, + lstm_hid_dim=self.lstm_hid_dim, + recon_n_layers=self.recon_n_layers, + recon_hid_dim=self.recon_hid_dim, + dropout=self.dropout + ) +
+ +
+ + + + + +
+ +
+
+
+ +
+ + + + +
+
+ +
+ +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/docs/_modules/ice/anomaly_detection/models/transformer.html b/docs/_modules/ice/anomaly_detection/models/transformer.html new file mode 100644 index 0000000..65be837 --- /dev/null +++ b/docs/_modules/ice/anomaly_detection/models/transformer.html @@ -0,0 +1,778 @@ + + + + + + + + + + + ice.anomaly_detection.models.transformer — ICE documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +

Source code for ice.anomaly_detection.models.transformer

+import torch
+from torch import nn
+import torch.nn.functional as F
+import numpy as np
+import math
+
+from ice.anomaly_detection.models.base import BaseAnomalyDetection
+
+
+"""
+The code of Anomaly Transformer is taken from official implementation:
+https://github.com/thuml/Anomaly-Transformer
+"""
+class TriangularCausalMask():
+    def __init__(self, B, L, device="cpu"):
+        mask_shape = [B, 1, L, L]
+        with torch.no_grad():
+            self._mask = torch.triu(torch.ones(mask_shape, dtype=torch.bool), diagonal=1).to(device)
+
+    @property
+    def mask(self):
+        return self._mask
+
+
+
[docs]class AnomalyAttention(nn.Module): + def __init__(self, win_size, mask_flag=True, scale=None, attention_dropout=0.0, output_attention=True, device="cpu"): + super(AnomalyAttention, self).__init__() + self.scale = scale + self.mask_flag = mask_flag + self.output_attention = output_attention + self.dropout = nn.Dropout(attention_dropout) + window_size = win_size + self.distances = torch.zeros((window_size, window_size)).to(device) + for i in range(window_size): + for j in range(window_size): + self.distances[i][j] = abs(i - j) + +
[docs] def forward(self, queries, keys, values, sigma, attn_mask): + B, L, H, E = queries.shape + _, S, _, D = values.shape + scale = self.scale or 1. / math.sqrt(E) + + scores = torch.einsum("blhe,bshe->bhls", queries, keys) + if self.mask_flag: + if attn_mask is None: + attn_mask = TriangularCausalMask(B, L, device=queries.device) + scores.masked_fill_(attn_mask.mask, -np.inf) + attn = scale * scores + + sigma = sigma.transpose(1, 2) # B L H -> B H L + window_size = attn.shape[-1] + sigma = torch.sigmoid(sigma * 5) + 1e-5 + sigma = torch.pow(3, sigma) - 1 + sigma = sigma.unsqueeze(-1).repeat(1, 1, 1, window_size) # B H L L + prior = self.distances.unsqueeze(0).unsqueeze(0).repeat(sigma.shape[0], sigma.shape[1], 1, 1).to(queries.device) + prior = 1.0 / (math.sqrt(2 * math.pi) * sigma) * torch.exp(-prior ** 2 / 2 / (sigma ** 2)) + + series = self.dropout(torch.softmax(attn, dim=-1)) + V = torch.einsum("bhls,bshd->blhd", series, values) + + if self.output_attention: + return (V.contiguous(), series, prior, sigma) + else: + return (V.contiguous(), None)
+ + +
[docs]class AttentionLayer(nn.Module): + def __init__(self, attention, d_model, n_heads, d_keys=None, + d_values=None): + super(AttentionLayer, self).__init__() + + d_keys = d_keys or (d_model // n_heads) + d_values = d_values or (d_model // n_heads) + self.norm = nn.LayerNorm(d_model) + self.inner_attention = attention + self.query_projection = nn.Linear(d_model, + d_keys * n_heads) + self.key_projection = nn.Linear(d_model, + d_keys * n_heads) + self.value_projection = nn.Linear(d_model, + d_values * n_heads) + self.sigma_projection = nn.Linear(d_model, + n_heads) + self.out_projection = nn.Linear(d_values * n_heads, d_model) + + self.n_heads = n_heads + +
[docs] def forward(self, queries, keys, values, attn_mask): + B, L, _ = queries.shape + _, S, _ = keys.shape + H = self.n_heads + x = queries + queries = self.query_projection(queries).view(B, L, H, -1) + keys = self.key_projection(keys).view(B, S, H, -1) + values = self.value_projection(values).view(B, S, H, -1) + sigma = self.sigma_projection(x).view(B, L, H) + + out, series, prior, sigma = self.inner_attention( + queries, + keys, + values, + sigma, + attn_mask + ) + out = out.view(B, L, -1) + + return self.out_projection(out), series, prior, sigma
+ + +
[docs]class PositionalEmbedding(nn.Module): + def __init__(self, d_model, max_len=5000): + super(PositionalEmbedding, self).__init__() + # Compute the positional encodings once in log space. + pe = torch.zeros(max_len, d_model).float() + pe.require_grad = False + + position = torch.arange(0, max_len).float().unsqueeze(1) + div_term = (torch.arange(0, d_model, 2).float() * -(math.log(10000.0) / d_model)).exp() + + pe[:, 0::2] = torch.sin(position * div_term) + pe[:, 1::2] = torch.cos(position * div_term) + + pe = pe.unsqueeze(0) + self.register_buffer('pe', pe) + +
[docs] def forward(self, x): + return self.pe[:, :x.size(1)]
+ + +
[docs]class TokenEmbedding(nn.Module): + def __init__(self, c_in, d_model): + super(TokenEmbedding, self).__init__() + padding = 1 if torch.__version__ >= '1.5.0' else 2 + self.tokenConv = nn.Conv1d(in_channels=c_in, out_channels=d_model, + kernel_size=3, padding=padding, padding_mode='circular', bias=False) + for m in self.modules(): + if isinstance(m, nn.Conv1d): + nn.init.kaiming_normal_(m.weight, mode='fan_in', nonlinearity='leaky_relu') + +
[docs] def forward(self, x): + x = self.tokenConv(x.permute(0, 2, 1)).transpose(1, 2) + return x
+ + +
[docs]class DataEmbedding(nn.Module): + def __init__(self, c_in, d_model, dropout=0.0): + super(DataEmbedding, self).__init__() + + self.value_embedding = TokenEmbedding(c_in=c_in, d_model=d_model) + self.position_embedding = PositionalEmbedding(d_model=d_model) + + self.dropout = nn.Dropout(p=dropout) + +
[docs] def forward(self, x): + x = self.value_embedding(x) + self.position_embedding(x) + return self.dropout(x)
+ + +
[docs]class EncoderLayer(nn.Module): + def __init__(self, attention, d_model, d_ff=None, dropout=0.1, activation="relu"): + super(EncoderLayer, self).__init__() + d_ff = d_ff or 4 * d_model + self.attention = attention + self.conv1 = nn.Conv1d(in_channels=d_model, out_channels=d_ff, kernel_size=1) + self.conv2 = nn.Conv1d(in_channels=d_ff, out_channels=d_model, kernel_size=1) + self.norm1 = nn.LayerNorm(d_model) + self.norm2 = nn.LayerNorm(d_model) + self.dropout = nn.Dropout(dropout) + self.activation = F.relu if activation == "relu" else F.gelu + +
[docs] def forward(self, x, attn_mask=None): + new_x, attn, mask, sigma = self.attention( + x, x, x, + attn_mask=attn_mask + ) + x = x + self.dropout(new_x) + y = x = self.norm1(x) + y = self.dropout(self.activation(self.conv1(y.transpose(-1, 1)))) + y = self.dropout(self.conv2(y).transpose(-1, 1)) + + return self.norm2(x + y), attn, mask, sigma
+ + +
[docs]class Encoder(nn.Module): + def __init__(self, attn_layers, norm_layer=None): + super(Encoder, self).__init__() + self.attn_layers = nn.ModuleList(attn_layers) + self.norm = norm_layer + +
[docs] def forward(self, x, attn_mask=None): + # x [B, L, D] + series_list = [] + prior_list = [] + sigma_list = [] + for attn_layer in self.attn_layers: + x, series, prior, sigma = attn_layer(x, attn_mask=attn_mask) + series_list.append(series) + prior_list.append(prior) + sigma_list.append(sigma) + + if self.norm is not None: + x = self.norm(x) + + return x, series_list, prior_list, sigma_list
+ + +
[docs]class AnomalyTransformerModel(nn.Module): + def __init__( + self, + win_size, + enc_in, + c_out, + d_model, + n_heads, + e_layers, + d_ff, + dropout, + activation, + device + ): + super(AnomalyTransformerModel, self).__init__() + + # Encoding + self.embedding = DataEmbedding(enc_in, d_model, dropout) + + # Encoder + self.encoder = Encoder( + [ + EncoderLayer( + AttentionLayer( + AnomalyAttention(win_size, False, attention_dropout=dropout, device=device), + d_model, n_heads), + d_model, + d_ff, + dropout=dropout, + activation=activation + ) for l in range(e_layers) + ], + norm_layer=torch.nn.LayerNorm(d_model) + ) + + self.projection = nn.Linear(d_model, c_out, bias=True) + +
[docs] def forward(self, x): + enc_out = self.embedding(x) + enc_out, series, prior, sigmas = self.encoder(enc_out) + enc_out = self.projection(enc_out) + + return enc_out # [B, L, D]
+ + +
[docs]class AnomalyTransformer(BaseAnomalyDetection): + """ + Anomaly Transformer was presented at ICLR 2022: "Anomaly Transformer: + Time Series Anomaly Detection with Association Discrepancy". + https://openreview.net/forum?id=LzQQ89U1qm_ + """ + def __init__( + self, + window_size: int = 100, + stride: int = 1, + batch_size: int = 128, + lr: float = 0.0001, + num_epochs: int = 10, + device: str = 'cpu', + verbose: bool = False, + name: str = 'transformer_anomaly_detection', + random_seed: int = 42, + val_ratio: float = 0.15, + save_checkpoints: bool = False, + threshold_level: float = 0.95, + d_model: int = 256, + n_heads: int = 8, + e_layers: int = 3, + d_ff: int = 256, + dropout: float = 0.0, + activation: str = 'gelu' + ): + """ + Args: + window_size (int): The window size to train the model. + stride (int): The time interval between first points of consecutive + sliding windows in training. + batch_size (int): The batch size to train the model. + lr (float): The larning rate to train the model. + num_epochs (float): The number of epochs to train the model. + device (str): The name of a device to train the model. `cpu` and + `cuda` are possible. + verbose (bool): If true, show the progress bar in training. + name (str): The name of the model for artifact storing. + random_seed (int): Seed for random number generation to ensure reproducible results. + val_ratio (float): Proportion of the dataset used for validation, between 0 and 1. + save_checkpoints (bool): If true, store checkpoints. + threshold_level (float): Takes a value from 0 to 1. It specifies + the quantile in the distribution of errors on the training + dataset at which the threshold value is set. + threshold_value (float): Threshold value is calculated after the model is trained. + It sets the error limit above which the data sample defines as anomaly. + d_model (int): Dimension of model. + n_heads (int): Number of heads. + e_layers (int): Number of encoder layers. + d_ff (int): Dimension of MLP. + dropout (float): The rate of dropout. + activation (str): Activation ('relu', 'gelu'). + """ + super().__init__( + window_size, stride, batch_size, lr, num_epochs, device, verbose, name, random_seed, + val_ratio, save_checkpoints, threshold_level + ) + self.d_model = d_model + self.n_heads = n_heads + self.e_layers = e_layers + self.d_ff = d_ff + self.dropout = dropout + self.activation = activation + + _param_conf_map = dict(BaseAnomalyDetection._param_conf_map, + **{ + "d_model": ["MODEL", "D_MODEL"], + "n_heads": ["MODEL", "N_HEADS"], + "e_layers": ["MODEL", "E_LAYERS"], + "d_ff": ["MODEL", "D_FF"], + "dropout": ["MODEL", "DROPOUT"], + "activation": ["MODEL", "ACTIVATION"] + } + ) + + def _create_model(self, input_dim: int, output_dim: int): + self.model = AnomalyTransformerModel( + win_size=self.window_size, + enc_in=input_dim, + c_out=input_dim, + d_model=self.d_model, + n_heads=self.n_heads, + e_layers=self.e_layers, + d_ff=self.d_ff, + dropout=self.dropout, + activation=self.activation, + device=self.device + )
+
+ +
+ + + + + +
+ +
+
+
+ +
+ + + + +
+
+ +
+ +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/docs/_modules/ice/base.html b/docs/_modules/ice/base.html index 69f01bd..4870df6 100644 --- a/docs/_modules/ice/base.html +++ b/docs/_modules/ice/base.html @@ -371,17 +371,22 @@

Source code for ice.base

 import pandas as pd
 import numpy as np
 import torch
-from tqdm.auto import tqdm
+from tqdm.auto import tqdm, trange
 import os
 import zipfile
 import requests
 import datetime
 import json
+import random
 from ice.configs import Config
+import time
+from torch.utils.data import DataLoader, Dataset, random_split
+import optuna
 
 
 
[docs]class BaseDataset(ABC): """Base class for datasets.""" + def __init__(self, num_chunks=None, force_download=False): """ Args: @@ -397,40 +402,55 @@

Source code for ice.base

         self.public_link = None
         self.set_name_public_link()
         self._load(num_chunks, force_download)
-    
+
 
-    
+
     def _load(self, num_chunks, force_download):
         """Load the dataset in self.df and self.target."""
-        ref_path = f'data/{self.name}/'
+        ref_path = f"data/{self.name}/"
         if not os.path.exists(ref_path):
             os.makedirs(ref_path)
-        zfile_path = f'data/{self.name}.zip'
+        zfile_path = f"data/{self.name}.zip"
 
         url = self._get_url(self.public_link)
         if not os.path.exists(zfile_path) or force_download:
             self._download_pgbar(url, zfile_path, self.name, num_chunks)
-            
+
         self._extracting_files(zfile_path, ref_path)
-        self.df = self._read_csv_pgbar(ref_path + 'df.csv', index_col=['run_id', 'sample'])
-        self.target = self._read_csv_pgbar(ref_path + 'target.csv', index_col=['run_id', 'sample'])['target']
-        self.train_mask = self._read_csv_pgbar(ref_path + 'train_mask.csv', index_col=['run_id', 'sample'])['train_mask']
+        self.df = self._read_csv_pgbar(
+            ref_path + "df.csv", index_col=["run_id", "sample"]
+        )
+        self.target = self._read_csv_pgbar(
+            ref_path + "target.csv", index_col=["run_id", "sample"]
+        )["target"]
+        self.train_mask = self._read_csv_pgbar(
+            ref_path + "train_mask.csv", index_col=["run_id", "sample"]
+        )["train_mask"]
         self.train_mask = self.train_mask.astype(bool)
         self.test_mask = ~self.train_mask
-    
+
     def _get_url(self, public_link):
-        r = requests.get(f'https://cloud-api.yandex.net/v1/disk/public/resources?public_key={public_link}')
-        return r.json()['file']
+        url = ""
+        r = requests.get(
+            f"https://cloud-api.yandex.net/v1/disk/public/resources?public_key={public_link}"
+        )
+        if r.status_code == 200:
+            url = r.json()["file"]
+        else:
+            raise Exception(r.json()["description"])
+        return url
 
-    def _read_csv_pgbar(self, csv_path, index_col, chunk_size=1024*100):
-        rows = sum(1 for _ in open(csv_path, 'r')) - 1
+    def _read_csv_pgbar(self, csv_path, index_col, chunk_size=1024 * 100):
+        rows = sum(1 for _ in open(csv_path, "r")) - 1
         chunk_list = []
-        with tqdm(total=rows, desc=f'Reading {csv_path}') as pbar:
-            for chunk in pd.read_csv(csv_path, index_col=index_col, chunksize=chunk_size):
+        with tqdm(total=rows, desc=f"Reading {csv_path}") as pbar:
+            for chunk in pd.read_csv(
+                csv_path, index_col=index_col, chunksize=chunk_size
+            ):
                 chunk_list.append(chunk)
                 pbar.update(len(chunk))
         df = pd.concat((f for f in chunk_list), axis=0)
@@ -439,14 +459,15 @@ 

Source code for ice.base

     def _download_pgbar(self, url, zfile_path, fname, num_chunks):
         resp = requests.get(url, stream=True)
         total = int(resp.headers.get("Content-Length"))
-        with open(zfile_path, 'wb') as file: 
+        with open(zfile_path, "wb") as file:
             with tqdm(
                 total=total,
-                desc=f'Downloading {fname}',
-                unit='B',
+                desc=f"Downloading {fname}",
+                unit="B",
                 unit_scale=True,
-                unit_divisor=1024) as pbar:
-                i = 0    
+                unit_divisor=1024,
+            ) as pbar:
+                i = 0
                 for data in resp.iter_content(chunk_size=1024):
                     if num_chunks is not None and num_chunks == i:
                         break
@@ -454,20 +475,21 @@ 

Source code for ice.base

                     pbar.update(len(data))
                     i += 1
 
-    def _extracting_files(self, zfile_path, ref_path, block_size=1024*10000):
-        with zipfile.ZipFile(zfile_path, 'r') as zfile:
+    def _extracting_files(self, zfile_path, ref_path, block_size=1024 * 10000):
+        with zipfile.ZipFile(zfile_path, "r") as zfile:
             for entry_info in zfile.infolist():
                 if os.path.exists(ref_path + entry_info.filename):
                     continue
                 input_file = zfile.open(entry_info.filename)
-                target_file = open(ref_path + entry_info.filename, 'wb')
+                target_file = open(ref_path + entry_info.filename, "wb")
                 block = input_file.read(block_size)
                 with tqdm(
-                    total=entry_info.file_size, 
-                    desc=f'Extracting {entry_info.filename}', 
-                    unit='B', 
-                    unit_scale=True, 
-                    unit_divisor=1024) as pbar:
+                    total=entry_info.file_size,
+                    desc=f"Extracting {entry_info.filename}",
+                    unit="B",
+                    unit_scale=True,
+                    unit_divisor=1024,
+                ) as pbar:
                     while block:
                         target_file.write(block)
                         block = input_file.read(block_size)
@@ -480,38 +502,57 @@ 

Source code for ice.base

     """Base class for all models."""
 
     _param_conf_map = {
-            "batch_size" : ["DATASET", "BATCH_SIZE"],
-            "lr" : ["OPTIMIZATION", "LR"],
-            "num_epochs" : ["OPTIMIZATION", "NUM_EPOCHS"],
-            "verbose" : ["VERBOSE"],
-            "device" : ["DEVICE"],
-            "name" : ["EXPERIMENT_NAME"]
-        }
+        "batch_size": ["DATASET", "BATCH_SIZE"],
+        "lr": ["OPTIMIZATION", "LR"],
+        "num_epochs": ["OPTIMIZATION", "NUM_EPOCHS"],
+        "verbose": ["VERBOSE"],
+        "device": ["DEVICE"],
+        "name": ["EXPERIMENT_NAME"],
+        "window_size": ["MODEL", "WINDOW_SIZE"],
+        "stride": ["MODEL", "STRIDE"],
+        "val_ratio": ["DATASET", "VAL_RATIO"],
+        "random_seed": ["SEED"],
+    }
 
     @abstractmethod
     def __init__(
-            self, 
-            batch_size: int, 
-            lr: float, 
-            num_epochs: int, 
-            device: str, 
-            verbose: bool,
-            name: str
-        ):
+        self,
+        window_size: int,
+        stride: int,
+        batch_size: int,
+        lr: float,
+        num_epochs: int,
+        device: str,
+        verbose: bool,
+        name: str,
+        random_seed: int,
+        val_ratio: float,
+        save_checkpoints: bool,
+    ):
         """
         Args:
+            window_size (int): The window size to train the model.
+            stride (int): The time interval between first points of consecutive
+                sliding windows in training.
             batch_size (int): The batch size to train the model.
             lr (float): The larning rate to train the model.
             num_epochs (float): The number of epochs to train the model.
-            device (str): The name of a device to train the model. `cpu` and 
+            device (str): The name of a device to train the model. `cpu` and
                 `cuda` are possible.
             verbose (bool): If true, show the progress bar in training.
             name (str): The name of the model for artifact storing.
+            random_seed (int): Seed for random number generation to ensure reproducible results.
+            val_ratio (float): Proportion of the dataset used for validation, between 0 and 1.
+            save_checkpoints (bool): If true, store checkpoints.
         """
         self._cfg = Config()
         self._cfg.path_set(["MODEL", "NAME"], self.__class__.__name__)
         self._output_dir = "outputs"
 
+        self.window_size = window_size
+        self.val_ratio = val_ratio
+        self.val_metrics = None
+        self.stride = stride
         self.batch_size = batch_size
         self.lr = lr
         self.num_epochs = num_epochs
@@ -519,17 +560,29 @@ 

Source code for ice.base

         self.verbose = verbose
         self.model = None
         self.name = name
+        self.random_seed = random_seed
+        self.save_checkpoints = save_checkpoints
+        self.input_dim = None
+        self.output_dim = None
+        self.train_time = "no date"
+        self.checkpoint_epoch = 0
+        self.direction = "minimize"
 
     def __setattr__(self, __name: str, __value: Any):
-        if __name not in ['cfg', 'param_conf_map'] and __name in self._param_conf_map.keys():
+        if (
+            __name not in ["cfg", "param_conf_map"]
+            and __name in self._param_conf_map.keys()
+        ):
             self._cfg.path_set(self._param_conf_map[__name], __value)
 
         super().__setattr__(__name, __value)
         if __name == "name":
-            self._training_path, self._inference_path = self._initialize_paths()
-    
+            self._training_path, self._inference_path, self._checkpoints_path = (
+                self._initialize_paths()
+            )
+
 
[docs] @classmethod - def from_config(cls, cfg : Config): + def from_config(cls, cfg: Config): """Create instance of the model class with parameters from config. Args: @@ -543,63 +596,48 @@

Source code for ice.base

 
         for key in cls._param_conf_map.keys():
             param_dict[key] = cfg.path_get(cls._param_conf_map[key])
-        
+
         return cls(**param_dict)
-
[docs] def fit(self, df: pd.DataFrame, target: pd.Series): +
[docs] def fit( + self, + df: pd.DataFrame, + target: pd.Series = None, + epochs: int = None, + save_path: str = None, + trial: optuna.Trial = None, + force_model_ctreation: bool = False, + ): """Fit (train) the model by a given dataset. Args: - df (pandas.DataFrame): A dataframe with sensor data. Index has - two columns: `run_id` and `sample`. All other columns a value of + df (pandas.DataFrame): A dataframe with sensor data. Index has + two columns: `run_id` and `sample`. All other columns a value of sensors. - target (pandas.Series): A series with target values. Indes has two - columns: `run_id` and `sample`. + target (pandas.Series): A series with target values. Index has two + columns: `run_id` and `sample`. It is omitted for anomaly + detection task. + epochs (int): The number of epochs for training step. If None, + self.num_epochs parameter is used. + save_path (str): Path to save checkpoints. If None, the path is + created automatically. + trial (optuna.Trial, None): optuna.Trial object created by optimize method. + force_model_ctreation (bool): force fit to create model for optimization study. """ - assert df.shape[0] == target.shape[0], f"target is incompatible with df by the length: {df.shape[0]} and {target.shape[0]}." - assert np.all(df.index == target.index), "target's index and df's index are not the same." - assert df.index.names == (['run_id', 'sample']), "An index should contain columns `run_id` and `sample`." - self._create_model(df, target) - assert self.model is not None, "Model creation error." - self._fit(df, target) + self.train_time = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S") + if epochs is None: + epochs = self.num_epochs + self._validate_inputs(df, target) + if self.model is None or force_model_ctreation: + self._set_dims(df, target) + self._create_model(self.input_dim, self.output_dim) + assert self.model is not None, "Model creation error." + self._prepare_for_training(self.input_dim, self.output_dim) + self._train_nn( + df=df, target=target, epochs=epochs, save_path=save_path, trial=trial + ) self._store_atrifacts_train()
- def _initialize_paths(self): - artifacts_path = os.path.join(self._output_dir, self.name) - training_path = os.path.join(artifacts_path, 'training') - inference_path = os.path.join(artifacts_path, 'inference') - - return training_path, inference_path - - def _store_atrifacts_train(self): - save_path = os.path.join(self._training_path, datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")) - os.makedirs(save_path, exist_ok= True) - self._cfg.to_yaml(os.path.join(save_path, 'config.yaml')) - - def _store_atrifacts_inference(self, metrics): - save_path = os.path.join(self._inference_path, datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")) - os.makedirs(save_path, exist_ok= True) - - self._cfg.to_yaml(os.path.join(save_path, 'config.yaml')) - with open(os.path.join(save_path, "metrics.json"), 'w') as json_file: - json.dump(metrics, json_file) - - @abstractmethod - def _create_model(self, df: pd.DataFrame, target: pd.Series): - """ - This method has to be implemented by all children. Create a torch - model for traing and prediction. - """ - pass - - @abstractmethod - def _fit(self, df: pd.DataFrame, target: pd.Series): - """ - This method has to be implemented by all children. Fit (train) the model - by a given dataset. - """ - pass -
[docs] @torch.no_grad() def predict(self, sample: torch.Tensor) -> torch.Tensor: """Make a prediction for a given batch of samples. @@ -608,7 +646,7 @@

Source code for ice.base

             sample (torch.Tensor): A tensor of the shape (B, L, C) where
                 B is the batch size, L is the sequence length, C is the number
                 of sensors.
-        
+
         Returns:
             torch.Tensor: A tensor with predictions of the shape (B,).
         """
@@ -616,32 +654,492 @@ 

Source code for ice.base

         self.model.to(self.device)
         return self._predict(sample)
- @abstractmethod - def _predict(self, sample: torch.Tensor) -> torch.Tensor: - """ - This method has to be implemented by all children. Make a prediction - for a given batch of samples. +
[docs] def optimize( + self, + df: pd.DataFrame, + target: pd.Series = None, + optimize_parameter: str = "batch_size", + optimize_range: tuple = (128, 256), + direction: str = "minimize", + n_trials: int = 5, + epochs: int = None, + optimize_metric: str = None, + ): + """Make the optuna study to return the best hyperparameter value on validation dataset + + Args: + df (pd.DataFrame): DataFrame to use method fit + optimize_parameter (str, optional): Model parameter to optimize. Defaults to 'batch_size'. + optimize_range (tuple, optional): Model parameter range for optuna trials. Defaults to (128, 256). + n_trials (int, optional): number of trials. Defaults to 5. + target (pd.Series, optional): target pd.Series to use method fit. Defaults to None. + epochs (int, optional): Epoch number to use method fit. Defaults to None. + optimize_metric (str): Metric on validation dataset to use as a target for hyperparameter optimization. + direction (str): "minimize" or "maximize" the target for hyperparameter optimization + """ - pass - -
[docs] @abstractmethod + param_type = type(self.__dict__[optimize_parameter]) + self.direction = direction + + defaults_torch_backends = ( + torch.backends.cudnn.deterministic, + torch.backends.cudnn.benchmark, + ) + self.dump = self._training_path + + # make torch deterministic behavior + torch.backends.cudnn.deterministic = True + torch.backends.cudnn.benchmark = False + torch.use_deterministic_algorithms(True) + os.environ["CUBLAS_WORKSPACE_CONFIG"] = ":16:8" + + if not epochs: + epochs = self.num_epochs + + def objective(trial): + + self._training_path = self.dump + """optuna objective + + Args: + trial (optuna.Trial): optuna trial object + + Raises: + AssertionError: Returns if optimize_parameter value is not numerical + + Returns: + float: best validation loss to perform optimization step + """ + if param_type == float: + suggested_param = trial.suggest_float( + optimize_parameter, optimize_range[0], optimize_range[1] + ) + elif param_type == int: + suggested_param = trial.suggest_int( + optimize_parameter, optimize_range[0], optimize_range[1] + ) + elif optimize_parameter == "lr": + suggested_param = trial.suggest_loguniform( + optimize_parameter, optimize_range[0], optimize_range[1] + ) + else: + raise AssertionError(f"{optimize_parameter} is not int or float value") + + setattr(self, optimize_parameter, suggested_param) + + if optimize_metric: + self.val_metrics = True + + self._training_path = ( + self._training_path + f"/parameter_{optimize_parameter} optimization" + ) + os.makedirs(self._training_path, exist_ok=True) + + self.checkpoint_epoch = 0 + print(f"trial step with {optimize_parameter} = {suggested_param}") + self.fit( + df=df, + epochs=epochs, + target=target, + trial=trial, + force_model_ctreation=True, + ) + # use the best key metric on validation dataset from training + # if there is no such metric, use the best validation loss + + if optimize_metric: + return self.best_validation_metrics[ + optimize_metric + ] # dict with all best metric achieved during training -> write it + else: + return self.best_val_loss + + study = optuna.create_study( + direction=direction, + pruner=optuna.pruners.PercentilePruner(25.0), + study_name=f"/parameter_{optimize_parameter} study", + ) + study.optimize(objective, n_trials=n_trials) + self._training_path = self.dump + + print(f"Best hyperparameters: {study.best_params}") + print(f"Best trial: {study.best_trial}") + + df_trials = study.trials_dataframe() + df_trials.to_csv( + self._training_path + + f"/parameter_{optimize_parameter} optimization" + + f"/parameter_{optimize_parameter}.csv", + index=False, + ) + + # restore standard torch deterministic values + torch.backends.cudnn.deterministic, torch.backends.cudnn.benchmark = ( + defaults_torch_backends + ) + del os.environ["CUBLAS_WORKSPACE_CONFIG"] + torch.use_deterministic_algorithms(False)
+ +
[docs] @torch.no_grad() def evaluate(self, df: pd.DataFrame, target: pd.Series) -> dict: - """This method has to be implemented by all children. Evaluate the - metrics. Docstring has to be rewritten so that all metrics are clearly - described. + """Evaluate the metrics: accuracy. Args: - df (pandas.DataFrame): A dataframe with sensor data. Index has - two columns: `run_id` and `sample`. All other columns a value of + df (pandas.DataFrame): A dataframe with sensor data. Index has + two columns: `run_id` and `sample`. All other columns a value of sensors. target (pandas.Series): A series with target values. Indes has two columns: `run_id` and `sample`. - + Returns: dict: A dictionary with metrics where keys are names of metrics and values are values of metrics. """ - pass
+ self._validate_inputs(df, target) + dataset = SlidingWindowDataset(df, target, window_size=self.window_size) + self.dataloader = DataLoader(dataset, batch_size=self.batch_size, shuffle=False) + target, pred = [], [] + for sample, _target in tqdm( + self.dataloader, desc="Steps ...", leave=False, disable=(not self.verbose) + ): + sample = sample.to(self.device) + target.append(_target) + pred.append(self.predict(sample)) + target = torch.concat(target).numpy() + pred = torch.concat(pred).numpy() + metrics = self._calculate_metrics(pred, target) + self._store_atrifacts_inference(metrics) + return metrics
+ +
[docs] @torch.no_grad() + def model_param_estimation(self): + """Calculate number of self.model parameters, mean and std for inference time + + Returns: + tuple: A tuple containing the number of parameters in the + model and the mean and standard deviation of model inference time. + """ + assert ( + self.model != None + ), "use model.fit() to create fitted model object before" + sample = iter(self.dataloader).__next__() + if len(sample) == 2: + x, y = sample + else: + x = sample + + dummy_input = torch.randn(1, x.shape[1], x.shape[2]).to(self.device) + repetitions = 500 + times = np.zeros((repetitions, 1)) + + if self.device == "cuda": + starter, ender = torch.cuda.Event(enable_timing=True), torch.cuda.Event( + enable_timing=True + ) + + for i in range(repetitions): + starter.record() + _ = self.model(dummy_input) + ender.record() + torch.cuda.synchronize() + curr_time = starter.elapsed_time(ender) + times[i] = curr_time + + else: + for i in range(repetitions): + start_time = time.time() + _ = self.model(dummy_input) + end_time = time.time() + + curr_time = (end_time - start_time) * 1000 # Convert to milliseconds + times[i] = curr_time + + mean_inference_time = np.sum(times) / repetitions + std_inference_time = np.std(times) + + num_params = sum(p.numel() for p in self.model.parameters()) + + return num_params, (mean_inference_time, std_inference_time)
+ + @abstractmethod + def _create_model(self, input_dim: int, output_dim: int): + """ + This method has to be implemented by all children. Create a torch + model for traing and prediction. + """ + pass + + @abstractmethod + def _prepare_for_training(self, input_dim: int, output_dim: int): + """ + This method has to be implemented by all children. Prepare the model + for training by a given dataset. + """ + pass + + @abstractmethod + def _calculate_metrics(self, pred: torch.tensor, target: torch.tensor) -> dict: + """ + This method has to be implemented by all children. Calculate metrics. + """ + pass + + @abstractmethod + def _predict(self, sample: torch.Tensor) -> torch.Tensor: + """ + This method has to be implemented by all children. Make a prediction + for a given batch of samples. + """ + pass + + @abstractmethod + def _set_dims(self, df: pd.DataFrame, target: pd.Series): + """ + This method has to be implemented by all children. Calculate input and + output dimensions of the model by the given dataset. + """ + pass + + def _validate_inputs(self, df: pd.DataFrame, target: pd.Series): + assert ( + df.shape[0] == target.shape[0] + ), f"target is incompatible with df by the length: {df.shape[0]} and {target.shape[0]}." + assert np.all( + df.index == target.index + ), "target's index and df's index are not the same." + assert df.index.names == ( + ["run_id", "sample"] + ), "An index should contain columns `run_id` and `sample`." + assert ( + len(df) >= self.window_size + ), "window size is larger than the length of df." + assert len(df) >= self.stride, "stride is larger than the length of df." + + def _train_nn( + self, + df: pd.DataFrame, + target: pd.Series, + epochs: int, + save_path: str, + trial: optuna.Trial, + ): + self.model.train() + self.model.to(self.device) + self.best_val_loss = ( + float("inf") if self.direction == "minimize" else float("-inf") + ) + self.best_validation_metrics = {} + self._set_seed() + + dataset = SlidingWindowDataset(df, target, window_size=self.window_size, stride=self.stride) + val_size = max(int(len(dataset) * self.val_ratio), 1) + train_size = len(dataset) - val_size + train_dataset, val_dataset = random_split( + dataset, + [train_size, val_size], + generator=torch.Generator().manual_seed(self.random_seed), + ) + + self.dataloader = DataLoader( + train_dataset, batch_size=self.batch_size, shuffle=True + ) + self.val_dataloader = DataLoader( + val_dataset, batch_size=self.batch_size, shuffle=False + ) + for e in trange( + self.checkpoint_epoch, + self.checkpoint_epoch + epochs, + desc="Epochs ...", + disable=(not self.verbose), + ): + for sample, target in tqdm( + self.dataloader, + desc="Steps ...", + leave=False, + disable=(not self.verbose), + ): + sample = sample.to(self.device) + target = target.to(self.device) + logits = self.model(sample) + loss = self.loss_fn(logits, target) + self.optimizer.zero_grad() + loss.backward() + self.optimizer.step() + if self.verbose: + print(f"Epoch {e+1}, Loss: {loss.item():.4f}") + self.checkpoint_epoch = e + 1 + if self.save_checkpoints: + self.save_checkpoint(save_path) + + val_loss, val_metrics = self._validate_nn() + + if self.direction == "minimize": + self.best_val_loss = ( + val_loss if val_loss < self.best_val_loss else self.best_val_loss + ) + else: + self.best_val_loss = ( + val_loss if val_loss > self.best_val_loss else self.best_val_loss + ) + + if self.val_metrics: + for key, value in val_metrics.items(): + if key not in self.best_validation_metrics: + self.best_validation_metrics[key] = value + else: + if self.direction == "minimize": + self.best_validation_metrics[key] = ( + value + if self.best_validation_metrics[key] > value + else self.best_validation_metrics[key] + ) + else: + self.best_validation_metrics[key] = ( + value + if self.best_validation_metrics[key] < value + else self.best_validation_metrics[key] + ) + + if self.verbose: + if self.val_metrics: + print( + f"Epoch {e+1}, Validation Loss: {val_loss:.4f}, Metrics: {val_metrics}" + ) + else: + print(f"Epoch {e+1}, Validation Loss: {val_loss:.4f}") + + if trial: + trial.report(val_loss, self.checkpoint_epoch) + + if trial.should_prune(): + raise optuna.exceptions.TrialPruned() + + def _validate_nn(self): + self.model.eval() + + val_loss = 0 + target_list, pred_list = [], [] + with torch.no_grad(): + for sample, target in self.val_dataloader: + sample = sample.to(self.device) + target = target.to(self.device) + logits = self.model(sample) + loss = self.loss_fn(logits, target) + val_loss += loss.item() + + if self.val_metrics: + pred = self.predict(sample) + target_list.append(target.cpu()) + pred_list.append(pred.cpu()) + + val_loss /= len(self.val_dataloader) + + if self.val_metrics: + target_tensor = torch.cat(target_list).numpy() + pred_tensor = torch.cat(pred_list).numpy() + + val_metrics = self._calculate_metrics(pred_tensor, target_tensor) + else: + val_metrics = None + + self.model.train() + + return val_loss, val_metrics + + def _set_seed(self): + torch.manual_seed(self.random_seed) + random.seed(self.random_seed) + np.random.seed(self.random_seed) + + def _initialize_paths(self): + artifacts_path = os.path.join(self._output_dir, self.name) + training_path = os.path.join(artifacts_path, "training") + inference_path = os.path.join(artifacts_path, "inference") + checkpoints_path = os.path.join(artifacts_path, "checkpoints") + return training_path, inference_path, checkpoints_path + + def _store_atrifacts_train(self): + save_path = os.path.join(self._training_path, self.train_time) + os.makedirs(save_path, exist_ok=True) + self._cfg.to_yaml(os.path.join(save_path, "config.yaml")) + + def _store_atrifacts_inference(self, metrics): + save_path = os.path.join(self._inference_path, self.train_time) + os.makedirs(save_path, exist_ok=True) + + self._cfg.to_yaml(os.path.join(save_path, "config.yaml")) + with open(os.path.join(save_path, "metrics.json"), "w") as json_file: + json.dump(metrics, json_file) + +
[docs] def save_checkpoint(self, save_path: str = None): + """Save checkpoint. + + Args: + save_path (str): Path to save checkpoint. + """ + if save_path is None: + checkpoints_path = os.path.join(self._checkpoints_path, self.train_time) + os.makedirs(checkpoints_path, exist_ok=True) + file_path = self.name + "_epoch_" + str(self.checkpoint_epoch) + save_path = os.path.join(checkpoints_path, file_path + ".tar") + torch.save( + { + "config": self._cfg, + "epoch": self.checkpoint_epoch, + "input_dim": self.input_dim, + "output_dim": self.output_dim, + "model_state_dict": self.model.state_dict(), + "optimizer_state_dict": self.optimizer.state_dict(), + }, + save_path, + )
+ +
[docs] def load_checkpoint(self, checkpoint_path: str): + """Load checkpoint. + + Args: + checkpoint_path (str): Path to load checkpoint. + """ + checkpoint = torch.load(checkpoint_path, map_location=self.device) + self._cfg = checkpoint["config"] + self.input_dim = checkpoint["input_dim"] + self.output_dim = checkpoint["output_dim"] + self._create_model(self.input_dim, self.output_dim) + self.model.to(self.device) + assert self.model is not None, "Model creation error." + self._prepare_for_training(self.input_dim, self.output_dim) + self.model.load_state_dict(checkpoint["model_state_dict"]) + self.optimizer.load_state_dict(checkpoint["optimizer_state_dict"]) + self.checkpoint_epoch = checkpoint["epoch"]
+ + +
[docs]class SlidingWindowDataset(Dataset): + def __init__( + self, df: pd.DataFrame, target: pd.Series, window_size: int, stride: int = 1 + ): + self.df = df + self.target = target + self.window_size = window_size + + window_end_indices = [] + run_ids = df.index.get_level_values(0).unique() + for run_id in tqdm(run_ids, desc="Creating sequence of samples"): + indices = np.array(df.index.get_locs([run_id])) + indices = indices[self.window_size :: stride] + window_end_indices.extend(indices) + self.window_end_indices = np.array(window_end_indices) + + def __len__(self): + return len(self.window_end_indices) + + def __getitem__(self, idx): + window_index = self.window_end_indices[idx] + sample = self.df.values[window_index - self.window_size : window_index] + if self.target is not None: + target = self.target.values[window_index] + else: + target = sample.astype("float32") + return sample.astype("float32"), target
diff --git a/docs/_modules/ice/fault_diagnosis/datasets.html b/docs/_modules/ice/fault_diagnosis/datasets.html index 42d66ab..82e834b 100644 --- a/docs/_modules/ice/fault_diagnosis/datasets.html +++ b/docs/_modules/ice/fault_diagnosis/datasets.html @@ -369,6 +369,20 @@

Source code for ice.fault_diagnosis.datasets

from ice.base import BaseDataset
 
 
+
[docs]class FaultDiagnosisRiethTEP(BaseDataset): + """ + Dataset of Tennessee Eastman Process dataset + Rieth, C. A., Amsel, B. D., Tran, R., & Cook, M. B. (2017). + Additional Tennessee Eastman Process Simulation Data for + Anomaly Detection Evaluation (Version V1) [Computer software]. + Harvard Dataverse. + https://doi.org/10.7910/DVN/6C3JR1. + """ +
+ +
[docs]class FaultDiagnosisSmallTEP(BaseDataset): """ Cropped version of Tennessee Eastman Process dataset diff --git a/docs/_modules/ice/fault_diagnosis/models/base.html b/docs/_modules/ice/fault_diagnosis/models/base.html index 6380b1c..79bafda 100644 --- a/docs/_modules/ice/fault_diagnosis/models/base.html +++ b/docs/_modules/ice/fault_diagnosis/models/base.html @@ -366,123 +366,43 @@

Source code for ice.fault_diagnosis.models.base

-from abc import ABC, abstractmethod
+from abc import ABC
 import pandas as pd
-from tqdm.auto import trange, tqdm
-
 import torch
 from torch import nn
 from torch.optim import Adam
-from torch.utils.data import DataLoader
 
-from ice.fault_diagnosis.utils import SlidingWindowDataset
 from ice.base import BaseModel
 from ice.fault_diagnosis.metrics import (
     accuracy, correct_daignosis_rate, true_positive_rate, false_positive_rate)
 
+
 
[docs]class BaseFaultDiagnosis(BaseModel, ABC): """Base class for all fault diagnosis models.""" - @abstractmethod - def __init__( - self, - window_size: int, - batch_size: int, - lr: float, - num_epochs: int, - device: str, - verbose: bool, - name: str - ): - """ - Args: - window_size (int): The window size to train the model. - batch_size (int): The batch size to train the model. - lr (float): The learning rate to train the model. - num_epochs (float): The number of epochs to train the model. - device (str): The name of a device to train the model. `cpu` and - `cuda` are possible. - verbose (bool): If true, show the progress bar in training. - name (str): The name of the model for artifact storing. - """ - super().__init__(batch_size, lr, num_epochs, device, verbose, name) - self._cfg.path_set(["TASK"], "fault_diagnosis") - - self.window_size = window_size - self.loss_fn = None - - _param_conf_map = dict(BaseModel._param_conf_map, - **{ - "window_size" : ["MODEL", "WINDOW_SIZE"] - } - ) - - def _fit(self, df: pd.DataFrame, target: pd.Series): - assert len(df) >= self.window_size, "window size is larger than the length of df." - num_classes = len(set(target)) - weight = torch.ones(num_classes, device=self.device) * 0.5 - weight[1:] /= num_classes - 1 + def _prepare_for_training(self, input_dim: int, output_dim: int): + weight = torch.ones(output_dim, device=self.device) * 0.5 + weight[1:] /= output_dim - 1 self.loss_fn = nn.CrossEntropyLoss(weight=weight) - self._train_nn(df, target) + self.optimizer = Adam(self.model.parameters(), lr=self.lr) def _predict(self, sample: torch.Tensor) -> torch.Tensor: sample = sample.to(self.device) logits = self.model(sample) return logits.argmax(axis=1).cpu() - def _train_nn(self, df: pd.DataFrame, target: pd.Series): - self.model.train() - self.model.to(self.device) - self.optimizer = Adam(self.model.parameters(), lr=self.lr) - - dataset = SlidingWindowDataset(df, target, window_size=self.window_size) - self.dataloader = DataLoader(dataset, batch_size=self.batch_size, shuffle=True) - for e in trange(self.num_epochs, desc='Epochs ...', disable=(not self.verbose)): - for sample, target in tqdm(self.dataloader, desc='Steps ...', leave=False, disable=(not self.verbose)): - sample = sample.to(self.device) - target = target.to(self.device) - logits = self.model(sample) - loss = self.loss_fn(logits, target) - self.optimizer.zero_grad() - loss.backward() - self.optimizer.step() - if self.verbose: - print(f'Epoch {e+1}, Loss: {loss.item():.4f}') - -
[docs] def evaluate(self, df: pd.DataFrame, target: pd.Series) -> dict: - """Evaluate the metrics: accuracy. - - Args: - df (pandas.DataFrame): A dataframe with sensor data. Index has - two columns: `run_id` and `sample`. All other columns a value of - sensors. - target (pandas.Series): A series with target values. Indes has two - columns: `run_id` and `sample`. - - Returns: - dict: A dictionary with metrics where keys are names of metrics and - values are values of metrics. - """ - dataset = SlidingWindowDataset(df, target, window_size=self.window_size) - self.dataloader = DataLoader(dataset, batch_size=self.batch_size, shuffle=True) - target, pred = [], [] - for sample, _target in tqdm( - self.dataloader, desc='Steps ...', leave=False, disable=(not self.verbose) - ): - sample = sample.to(self.device) - target.append(_target) - with torch.no_grad(): - pred.append(self.predict(sample)) - target = torch.concat(target).numpy() - pred = torch.concat(pred).numpy() + def _calculate_metrics(self, pred: torch.tensor, target: torch.tensor) -> dict: metrics = { 'accuracy': accuracy(pred, target), 'correct_daignosis_rate': correct_daignosis_rate(pred, target), 'true_positive_rate': true_positive_rate(pred, target), 'false_positive_rate': false_positive_rate(pred, target), } - self._store_atrifacts_inference(metrics) - return metrics
+ return metrics + + def _set_dims(self, df: pd.DataFrame, target: pd.Series): + self.input_dim = df.shape[1] + self.output_dim = len(set(target))
diff --git a/docs/_modules/ice/fault_diagnosis/models/mlp.html b/docs/_modules/ice/fault_diagnosis/models/mlp.html index 736beff..0ade77f 100644 --- a/docs/_modules/ice/fault_diagnosis/models/mlp.html +++ b/docs/_modules/ice/fault_diagnosis/models/mlp.html @@ -380,13 +380,17 @@

Source code for ice.fault_diagnosis.models.mlp

def __init__( self, window_size: int, + stride: int = 1, hidden_dim: int=256, batch_size: int=128, lr: float=0.001, num_epochs: int=10, device: str='cpu', verbose: bool=False, - name: str='mlp_fault_diagnosis' + name: str='mlp_fault_diagnosis', + random_seed: int = 42, + val_ratio: float = 0.15, + save_checkpoints: bool = False ): """ Args: @@ -399,10 +403,14 @@

Source code for ice.fault_diagnosis.models.mlp

`cuda` are possible. verbose (bool): If true, show the progress bar in training. name (str): The name of the model for artifact storing. + random_seed (int): Seed for random number generation to ensure reproducible results. + val_ratio (float): Proportion of the dataset used for validation, between 0 and 1. + save_checkpoints (bool): If true, store checkpoints. """ super().__init__( - window_size, batch_size, lr, num_epochs, device, verbose, name + window_size, stride, batch_size, lr, num_epochs, device, verbose, name, random_seed, val_ratio, save_checkpoints ) + self.val_metrics = True self.hidden_dim = hidden_dim @@ -412,14 +420,12 @@

Source code for ice.fault_diagnosis.models.mlp

} ) - def _create_model(self, df: DataFrame, target: Series): - num_sensors = df.shape[1] - num_classes = len(set(target)) + def _create_model(self, input_dim: int, output_dim: int): self.model = nn.Sequential( nn.Flatten(), - nn.Linear(num_sensors * self.window_size, self.hidden_dim), + nn.Linear(input_dim * self.window_size, self.hidden_dim), nn.ReLU(), - nn.Linear(self.hidden_dim, num_classes), + nn.Linear(self.hidden_dim, output_dim), )

diff --git a/docs/_modules/ice/fault_diagnosis/models/tcn.html b/docs/_modules/ice/fault_diagnosis/models/tcn.html index fa58700..f196d4f 100644 --- a/docs/_modules/ice/fault_diagnosis/models/tcn.html +++ b/docs/_modules/ice/fault_diagnosis/models/tcn.html @@ -493,6 +493,7 @@

Source code for ice.fault_diagnosis.models.tcn

def __init__( self, window_size: int, + stride: int = 1, hidden_dim: int=256, kernel_size: int=5, num_layers: int=4, @@ -503,7 +504,10 @@

Source code for ice.fault_diagnosis.models.tcn

num_epochs: int=10, device: str='cpu', verbose: bool=False, - name: str='tcn_fault_diagnosis' + name: str='tcn_fault_diagnosis', + random_seed: int = 42, + val_ratio: float = 0.15, + save_checkpoints: bool = False ): """ Args: @@ -520,10 +524,14 @@

Source code for ice.fault_diagnosis.models.tcn

`cuda` are possible. verbose (bool): If true, show the progress bar in training. name (str): The name of the model for artifact storing. + random_seed (int): Seed for random number generation to ensure reproducible results. + val_ratio (float): Proportion of the dataset used for validation, between 0 and 1. + save_checkpoints (bool): If true, store checkpoints. """ super().__init__( - window_size, batch_size, lr, num_epochs, device, verbose, name + window_size, stride, batch_size, lr, num_epochs, device, verbose, name, random_seed, val_ratio, save_checkpoints ) + self.val_metrics = True self.hidden_dim = hidden_dim self.kernel_size = kernel_size @@ -541,16 +549,14 @@

Source code for ice.fault_diagnosis.models.tcn

} ) - def _create_model(self, df: DataFrame, target: Series): - num_sensors = df.shape[1] - num_classes = len(set(target)) + def _create_model(self, input_dim: int, output_dim: int): self.model = _TCNModule( - input_dim=num_sensors, + input_dim=input_dim, kernel_size=self.kernel_size, hidden_dim=self.hidden_dim, num_layers=self.num_layers, dilation_base=self.dilation_base, - output_dim=num_classes, + output_dim=output_dim, dropout=self.dropout, seq_len=self.window_size, )

diff --git a/docs/_modules/ice/health_index_estimation/datasets.html b/docs/_modules/ice/health_index_estimation/datasets.html index 0ce534d..168321c 100644 --- a/docs/_modules/ice/health_index_estimation/datasets.html +++ b/docs/_modules/ice/health_index_estimation/datasets.html @@ -419,6 +419,7 @@

Source code for ice.health_index_estimation.datasets

inter_func = [] for i in range(15): + data[i]["material"] = data[i]["material"].astype("float64") y = data[i].dropna().VB x = data[i].dropna().time @@ -432,21 +433,16 @@

Source code for ice.health_index_estimation.datasets

else: data[i] = data[i].fillna(0) - self.df = [data[i].drop(columns=["VB"]) for i in train_nums] + self.df = [ + data[i].drop(columns=["VB", "Unnamed: 0", "case", "run"]) + for i in train_nums + ] self.target = [data[i]["VB"] for i in train_nums] - self.test = [data[i].drop(columns=["VB"]) for i in test_nums] - self.test_target = [data[i]["VB"] for i in test_nums] - - def _read_csv_pgbar(self, csv_path, index_col, chunksize=1024 * 100): - df = pd.read_csv(csv_path) - df.rename(columns={"cut_no": "run_id"}, inplace=True) - df = df.set_index(["run_id", "sample"]).drop( - columns=["Unnamed: 0", "case", "run"] - ) - df["material"] = df["material"].astype("float64") - - return df
+ self.test = [ + data[i].drop(columns=["VB", "Unnamed: 0", "case", "run"]) for i in test_nums + ] + self.test_target = [data[i]["VB"] for i in test_nums]
diff --git a/docs/_modules/ice/health_index_estimation/metrics.html b/docs/_modules/ice/health_index_estimation/metrics.html index 9dfbdcf..6ded8b2 100644 --- a/docs/_modules/ice/health_index_estimation/metrics.html +++ b/docs/_modules/ice/health_index_estimation/metrics.html @@ -381,6 +381,19 @@

Source code for ice.health_index_estimation.metrics

float: rmse """ return float(np.mean((pred - target) ** 2))
+ +
[docs]def rmse(pred: list, target: list) -> float: + """ + Mean squared error between real and predicted wear. + + Args: + pred (list): numpy prediction values. + target (list): numpy target values. + + Returns: + float: rmse + """ + return float(np.sqrt(np.mean((pred - target) ** 2)))
diff --git a/docs/_modules/ice/health_index_estimation/models/base.html b/docs/_modules/ice/health_index_estimation/models/base.html index 2fc2116..8f1c574 100644 --- a/docs/_modules/ice/health_index_estimation/models/base.html +++ b/docs/_modules/ice/health_index_estimation/models/base.html @@ -367,134 +367,37 @@

Source code for ice.health_index_estimation.models.base

 from ice.base import BaseModel
-from abc import ABC, abstractmethod
+from abc import ABC
 import pandas as pd
-from tqdm.auto import trange, tqdm
-
-from torch.optim import Adam, AdamW
-from torch.utils.data import DataLoader
+from torch.optim import AdamW
 import torch
 from torch import nn
-from ice.health_index_estimation.utils import SlidingWindowDataset
-from ice.health_index_estimation.metrics import mse
+
+from ice.health_index_estimation.metrics import mse, rmse
 
 
 
[docs]class BaseHealthIndexEstimation (BaseModel, ABC): """Base class for all HI diagnosis models.""" - @abstractmethod - def __init__( - self, - window_size: int, - stride: int, - batch_size: int, - lr: float, - num_epochs: int, - device: str, - verbose: bool, - name: str, - ): - """ - Args: - window_size (int): The window size to train the model. - stride (int): The time interval between first points of consecutive sliding windows. - batch_size (int): The batch size to train the model. - lr (float): The larning rate to train the model. - num_epochs (float): The number of epochs to train the model. - device (str): The name of a device to train the model. `cpu` and - `cuda` are possible. - verbose (bool): If true, show the progress bar in training. - name (str): The name of the model for artifact storing. - """ - super().__init__(batch_size, lr, num_epochs, device, verbose, name) - - self.window_size = window_size - self.stride = stride - self.loss_fn = None - self.newvalues = None - - self.test_stride = 50 - - _param_conf_map = dict( - BaseModel._param_conf_map, - **{"window_size": ["MODEL", "WINDOW_SIZE"], "stride": ["MODEL", "STRIDE"]}, - ) - - def _fit(self, df: pd.DataFrame, target: pd.Series): - assert ( - len(df) >= self.window_size - ), "window size is larger than the length of df." - assert len(df) >= self.stride, "stride is larger than the length of df." + def _prepare_for_training(self, input_dim: int, output_dim: int): self.loss_fn = nn.L1Loss() - self._train_nn(df, target) + self.optimizer = AdamW(self.model.parameters(), lr=self.lr) def _predict(self, sample: torch.Tensor) -> torch.Tensor: sample = sample.to(self.device) predicted_rul = self.model(sample) return predicted_rul.cpu() - def _train_nn(self, df: pd.DataFrame, target: pd.Series): - self.model.train() - self.model.to(self.device) - self.optimizer = AdamW(self.model.parameters(), lr=self.lr) - - dataset = SlidingWindowDataset( - df, target, window_size=self.window_size, stride=self.stride - ) - self.dataloader = DataLoader(dataset, batch_size=self.batch_size, shuffle=True) - for e in trange(self.num_epochs, desc="Epochs ...", disable=(not self.verbose)): - for sample, target in tqdm( - self.dataloader, - desc="Steps ...", - leave=False, - disable=(not self.verbose), - ): - sample = sample.to(self.device) - target = target.to(self.device) - - logits = self.model(sample) - loss = self.loss_fn(logits, target) - - self.optimizer.zero_grad() - loss.backward() - self.optimizer.step() - self.newvalues.append(loss.item()) - if self.verbose: - print(f"Epoch {e+1}, Loss: {loss.item():.4f}") - -
[docs] def evaluate(self, df: pd.DataFrame, target: pd.Series) -> dict: - """Evaluate the metrics: mse. - - Args: - df (pandas.DataFrame): A dataframe with sensor data. Index has - two columns: `run_id` and `sample`. All other columns a value of - sensors. - target (pandas.Series): A series with target values. Indes has two - columns: `run_id` and `sample`. - - Returns: - dict: A dictionary with metrics where keys are names of metrics and - values are values of metrics. - """ - dataset = SlidingWindowDataset( - df, target, window_size=self.window_size, stride=self.test_stride - ) - self.dataloader = DataLoader(dataset, batch_size=1, shuffle=True) - target, pred = [], [] - for sample, _target in tqdm( - self.dataloader, desc="Steps ...", leave=False, disable=(not self.verbose) - ): - sample = sample.to(self.device) - target.append(_target) - with torch.no_grad(): - pred.append(self.predict(sample)) - target = torch.concat(target).numpy() - pred = torch.concat(pred).numpy() + def _calculate_metrics(self, pred: torch.tensor, target: torch.tensor) -> dict: metrics = { "mse": mse(pred, target), + "rmse": rmse(pred, target), } - self._store_atrifacts_inference(metrics) - return metrics
+ return metrics + + def _set_dims(self, df: pd.DataFrame, target: pd.Series): + self.input_dim = df.shape[1] + self.output_dim = 1
diff --git a/docs/_modules/ice/health_index_estimation/models/mlp.html b/docs/_modules/ice/health_index_estimation/models/mlp.html index 39c637a..188788b 100644 --- a/docs/_modules/ice/health_index_estimation/models/mlp.html +++ b/docs/_modules/ice/health_index_estimation/models/mlp.html @@ -390,6 +390,9 @@

Source code for ice.health_index_estimation.models.mlp

device: str = "cpu", verbose: bool = True, name: str = "mlp_fault_diagnosis", + random_seed: int = 42, + val_ratio: float = 0.15, + save_checkpoints: bool = False ): """ Args: @@ -403,10 +406,14 @@

Source code for ice.health_index_estimation.models.mlp

`cuda` are possible. verbose (bool): If true, show the progress bar in training. name (str): The name of the model for artifact storing. + random_seed (int): Seed for random number generation to ensure reproducible results. + val_ratio (float): Proportion of the dataset used for validation, between 0 and 1. + save_checkpoints (bool): If true, store checkpoints. """ super().__init__( - window_size, stride, batch_size, lr, num_epochs, device, verbose, name + window_size, stride, batch_size, lr, num_epochs, device, verbose, name, random_seed, val_ratio, save_checkpoints ) + self.val_metrics = True self.hidden_dim = hidden_dim self.newvalues = [] @@ -416,12 +423,13 @@

Source code for ice.health_index_estimation.models.mlp

**{"hidden_dim": ["MODEL", "HIDDEN_DIM"]} ) - def _create_model(self, df: DataFrame, target: Series): - num_sensors = df.shape[1] + def _create_model(self, input_dim: int, output_dim: int): self.model = nn.Sequential( nn.Flatten(), - nn.Linear(num_sensors * self.window_size, self.hidden_dim), + nn.Dropout(0.5), + nn.Linear(input_dim * self.window_size, self.hidden_dim), nn.ReLU(), + nn.Dropout(0.5), nn.Linear(self.hidden_dim, 1), nn.Flatten(start_dim=0), )
diff --git a/docs/_modules/ice/remaining_useful_life_estimation/datasets.html b/docs/_modules/ice/remaining_useful_life_estimation/datasets.html index 9787a0f..c7a9020 100644 --- a/docs/_modules/ice/remaining_useful_life_estimation/datasets.html +++ b/docs/_modules/ice/remaining_useful_life_estimation/datasets.html @@ -398,7 +398,7 @@

Source code for ice.remaining_useful_life_estimation.datasets

if not os.path.exists(zfile_path) or force_download: self._download_pgbar(url, zfile_path, self.name, num_chunks) - self._extracting_files(zfile_path, ref_path) + self._extracting_files(zfile_path, "data/") self.df = [ self._read_csv_pgbar( ref_path + f"fd{i}_train.csv", index_col=["run_id", "sample"] @@ -422,13 +422,50 @@

Source code for ice.remaining_useful_life_estimation.datasets

ref_path + f"fd{i}_test.csv", index_col=["run_id", "sample"] )["rul"] for i in range(1, 5) - ] + ]
+ + +
[docs]class RulCmapssPaper(BaseDataset): + """ + Preprocessed to piece wise RUL data from the dataset: + Saxena A. et al. Damage propagation modeling for aircraft engine run-to-failure simulation + DOI: 10.1109/PHM.2008.4711414. Target is the minimum rul value for every test device. + + """ + + + + def _load(self, num_chunks, force_download): + """ + Load the test dataset in list obects: self.df, self.target, self.test and self.test_target. + 4 subdatasets fd001-fd004, list index corresponds to a subdataset number + + """ + ref_path = f"data/{self.name}/" + if not os.path.exists(ref_path): + os.makedirs(ref_path) + zfile_path = f"data/{self.name}.zip" - def _read_csv_pgbar(self, csv_path, index_col, chunksize=1024 * 100): - df = pd.read_csv(csv_path) - df.rename(columns={"unit_num": "run_id"}, inplace=True) - df = df.set_index(["run_id", "sample"]) - return df
+ url = self._get_url(self.public_link) + if not os.path.exists(zfile_path) or force_download: + self._download_pgbar(url, zfile_path, self.name, num_chunks) + + self._extracting_files(zfile_path, f"data/{self.name}/") + + self.test = [ + self._read_csv_pgbar( + ref_path + f"fd{i}_test.csv", index_col=["run_id", "sample"] + ).drop(columns=["rul"]) + for i in range(1, 5) + ] + self.test_target = [ + self._read_csv_pgbar( + ref_path + f"/fd{i}_test.csv", index_col=["run_id", "sample"] + )["rul"] + for i in range(1, 5) + ]
diff --git a/docs/_modules/ice/remaining_useful_life_estimation/metrics.html b/docs/_modules/ice/remaining_useful_life_estimation/metrics.html index 0bf0393..18f3641 100644 --- a/docs/_modules/ice/remaining_useful_life_estimation/metrics.html +++ b/docs/_modules/ice/remaining_useful_life_estimation/metrics.html @@ -397,7 +397,7 @@

Source code for ice.remaining_useful_life_estimation.metrics

return float(np.exp((-value / 13)) - 1 if value < 0 else np.exp((value / 10)) - 1)
-
[docs]def score(pred: list, target: list) -> float: +
[docs]def cmapss_score(pred: list, target: list) -> float: """ Non-simmetric metric proposed in the original dataset paper. DOI: 10.1109/PHM.2008.4711414 diff --git a/docs/_modules/ice/remaining_useful_life_estimation/models/base.html b/docs/_modules/ice/remaining_useful_life_estimation/models/base.html index 52b7803..a1814c6 100644 --- a/docs/_modules/ice/remaining_useful_life_estimation/models/base.html +++ b/docs/_modules/ice/remaining_useful_life_estimation/models/base.html @@ -367,132 +367,37 @@

Source code for ice.remaining_useful_life_estimation.models.base

 from ice.base import BaseModel
-from abc import ABC, abstractmethod
+from abc import ABC
 import pandas as pd
-from tqdm.auto import trange, tqdm
-
-from torch.optim import Adam, AdamW
-from torch.utils.data import DataLoader
+from torch.optim import AdamW
 import torch
 from torch import nn
-from ice.remaining_useful_life_estimation.utils import SlidingWindowDataset
-from ice.remaining_useful_life_estimation.metrics import rmse, score
+
+from ice.remaining_useful_life_estimation.metrics import rmse, cmapss_score
 
 
 
[docs]class BaseRemainingUsefulLifeEstimation(BaseModel, ABC): """Base class for all RUL models.""" - @abstractmethod - def __init__( - self, - window_size: int, - stride: int, - batch_size: int, - lr: float, - num_epochs: int, - device: str, - verbose: bool, - name: str, - ): - """ - Args: - window_size (int): The window size to train the model. - stride (int): The time interval between first points of consecutive sliding windows. - batch_size (int): The batch size to train the model. - lr (float): The learning rate to train the model. - num_epochs (float): The number of epochs to train the model. - device (str): The name of a device to train the model. `cpu` and - `cuda` are possible. - verbose (bool): If true, show the progress bar in training. - name (str): The name of the model for artifact storing. - """ - super().__init__(batch_size, lr, num_epochs, device, verbose, name) - - self.window_size = window_size - self.stride = stride - self.loss_fn = None - self.loss_array = None - - _param_conf_map = dict( - BaseModel._param_conf_map, - **{ - "window_size": ["MODEL", "WINDOW_SIZE"], - "stride": ["MODEL", "STRIDE"], - }, - ) - - def _fit(self, df: pd.DataFrame, target: pd.Series): - assert ( - len(df) >= self.window_size - ), "window size is larger than the length of df." - assert len(df) >= self.stride, "stride is larger than the length of df." + def _prepare_for_training(self, input_dim: int, output_dim: int): self.loss_fn = nn.L1Loss() - self._train_nn(df, target) + self.optimizer = AdamW(self.model.parameters(), lr=self.lr) def _predict(self, sample: torch.Tensor) -> torch.Tensor: sample = sample.to(self.device) predicted_rul = self.model(sample) return predicted_rul.cpu() - def _train_nn(self, df: pd.DataFrame, target: pd.Series): - self.model.train() - self.model.to(self.device) - self.optimizer = AdamW(self.model.parameters(), lr=self.lr) - - dataset = SlidingWindowDataset( - df, target, window_size=self.window_size, stride=self.stride - ) - self.dataloader = DataLoader(dataset, batch_size=self.batch_size, shuffle=True) - for e in trange(self.num_epochs, desc="Epochs ...", disable=(not self.verbose)): - for sample, target in tqdm( - self.dataloader, - desc="Steps ...", - leave=False, - disable=(not self.verbose), - ): - sample = sample.to(self.device) - target = target.to(self.device) - logits = self.model(sample) - loss = self.loss_fn(logits, target) - self.optimizer.zero_grad() - loss.backward() - self.optimizer.step() - self.loss_array.append(loss.item()) - if self.verbose: - print(f"Epoch {e+1}, Loss: {loss.item():.4f}") - -
[docs] def evaluate(self, df: pd.DataFrame, target: pd.Series) -> dict: - """Evaluate the metrics: rmse, c-mapss score. - - Args: - df (pandas.DataFrame): A dataframe with sensor data. Index has - two columns: `run_id` and `sample`. All other columns a value of - sensors. - target (pandas.Series): A series with target values. Indes has two - columns: `run_id` and `sample`. - - Returns: - dict: A dictionary with metrics where keys are names of metrics and - values are values of metrics. - """ - dataset = SlidingWindowDataset(df, target, window_size=self.window_size) - self.dataloader = DataLoader(dataset, batch_size=1, shuffle=True) - target, pred = [], [] - for sample, _target in tqdm( - self.dataloader, desc="Steps ...", leave=False, disable=(not self.verbose) - ): - sample = sample.to(self.device) - target.append(_target) - with torch.no_grad(): - pred.append(self.predict(sample)) - target = torch.concat(target).numpy() - pred = torch.concat(pred).numpy() + def _calculate_metrics(self, pred: torch.tensor, target: torch.tensor) -> dict: metrics = { "rmse": rmse(pred, target), - "score": score(pred, target), + "cmapss_score": cmapss_score(pred, target), } - self._store_atrifacts_inference(metrics) - return metrics
+ return metrics + + def _set_dims(self, df: pd.DataFrame, target: pd.Series): + self.input_dim = df.shape[1] + self.output_dim = 1
diff --git a/docs/_modules/ice/remaining_useful_life_estimation/models/lstm.html b/docs/_modules/ice/remaining_useful_life_estimation/models/lstm.html new file mode 100644 index 0000000..2fa856b --- /dev/null +++ b/docs/_modules/ice/remaining_useful_life_estimation/models/lstm.html @@ -0,0 +1,556 @@ + + + + + + + + + + + ice.remaining_useful_life_estimation.models.lstm — ICE documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+
+
+
+
+ + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +

Source code for ice.remaining_useful_life_estimation.models.lstm

+from torch import nn
+from ice.remaining_useful_life_estimation.models.base import BaseRemainingUsefulLifeEstimation
+from pandas import DataFrame, Series
+import torch
+
+
+
[docs]class LSTM_model(nn.Module): + """ + Long short-term memory (LSTM) is reccurent neural network type, + pytorch realisation https://pytorch.org/docs/stable/generated/torch.nn.LSTM.html + """ + def __init__( + self, + input_dim, + hidden_size=512, + device="cpu", + num_layers=2,): + """ + Args: + input_dim (int): The dimension size of input data, related to the sensor amount in industry probles. + hidden_size (int): The number of features in the hidden state of the model. + device (str): The name of a device to train the model. `cpu` and `cuda` are possible. + num_layers (int): The number of stacked reccurent layers of the classic LSTM architecture. + """ + super(LSTM_model, self).__init__() + self.input_dim = input_dim + self.hidden_size = hidden_size + self.num_layers = num_layers + self.device = device + + self.lstm = nn.LSTM(input_size=input_dim, hidden_size=hidden_size, + num_layers=num_layers, batch_first=True) + +
[docs] def forward(self, x): + h_0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(self.device) #hidden state + c_0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(self.device) #internal state + + output, (hn, cn) = self.lstm(x, (h_0, c_0)) + return output[:, -1, :]
+ +
[docs]class LSTM(BaseRemainingUsefulLifeEstimation): + """ + Long short-term memory (LSTM) model consists of the classical LSTM architecture stack and + two-layer MLP with SiLU nonlinearity and dropout to make the final prediction. + + Each sample is moved to LSTM and reshaped to a vector (B, L, C) -> (B, hidden_size, C) + Then the sample is reshaped to a vector (B, hidden_size, C) -> (B, hidden_size * C) + """ + + def __init__( + self, + window_size: int = 32, + stride: int = 1, + hidden_dim: int = 512, + hidden_size: int = 256, + num_layers: int =2, + dropout_value: float = 0.5, + batch_size: int = 64, + lr: float = 1e-4, + num_epochs: int = 35, + device: str = "cpu", + verbose: bool = True, + name: str = "mlp_cmapss_rul", + random_seed: int = 42, + val_ratio: float = 0.15, + save_checkpoints: bool = False + ): + """ + Args: + window_size (int): The window size to train the model. + stride (int): The time interval between first points of consecutive sliding windows. + hidden_dim (int): The dimensionality of the hidden layer in MLP. + hidden_size (int): The number of features in the hidden state of the model. + num_layers (int): The number of stacked reccurent layers of the classic LSTM architecture. + batch_size (int): The batch size to train the model. + lr (float): The larning rate to train the model. + num_epochs (float): The number of epochs to train the model. + device (str): The name of a device to train the model. `cpu` and + `cuda` are possible. + verbose (bool): If true, show the progress bar in training. + name (str): The name of the model for artifact storing. + random_seed (int): Seed for random number generation to ensure reproducible results. + val_ratio (float): Proportion of the dataset used for validation, between 0 and 1. + save_checkpoints (bool): If true, store checkpoints. + """ + super().__init__( + window_size, stride, batch_size, lr, num_epochs, device, verbose, name, random_seed, val_ratio, save_checkpoints + ) + self.val_metrics = True + + self.hidden_dim = hidden_dim + self.hidden_size = hidden_size + self.num_layers = num_layers + self.device = device + self.dropout_value = dropout_value + + self.loss_array = [] + + _param_conf_map = dict( + BaseRemainingUsefulLifeEstimation._param_conf_map, + **{"hidden_dim": ["MODEL", "HIDDEN_DIM"], + "hidden_size": ["MODEL", "HIDDEN_SIZE"], + "num_layers": ["MODEL", "NUM_LAYERS"], + "dropout_value": ["MODEL", "DROPOUT"], + } + ) + + def _create_model(self, input_dim: int, output_dim: int): + self.model = nn.Sequential( + nn.Dropout(self.dropout_value), + LSTM_model(input_dim, self.hidden_size, self.device, self.num_layers), + nn.Flatten(), + nn.Linear(self.hidden_size, self.hidden_dim), + nn.SiLU(), + nn.Dropout(self.dropout_value), + nn.Linear(self.hidden_dim, 1), + nn.Flatten(start_dim=0), + )
+
+ +
+ + + + + +
+ +
+
+
+ +
+ + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/_modules/ice/remaining_useful_life_estimation/models/mlp.html b/docs/_modules/ice/remaining_useful_life_estimation/models/mlp.html index f5e0c46..7f67280 100644 --- a/docs/_modules/ice/remaining_useful_life_estimation/models/mlp.html +++ b/docs/_modules/ice/remaining_useful_life_estimation/models/mlp.html @@ -383,13 +383,16 @@

Source code for ice.remaining_useful_life_estimation.models.mlp

self, window_size: int = 32, stride: int = 1, - hidden_dim: int = 256, - batch_size: int = 256, - lr: float = 5e-5, - num_epochs: int = 50, + hidden_dim: int = 512, + batch_size: int = 64, + lr: float = 1e-4, + num_epochs: int = 15, device: str = "cpu", verbose: bool = True, name: str = "mlp_cmapss_rul", + random_seed: int = 42, + val_ratio: float = 0.15, + save_checkpoints: bool = False ): """ Args: @@ -403,10 +406,14 @@

Source code for ice.remaining_useful_life_estimation.models.mlp

`cuda` are possible. verbose (bool): If true, show the progress bar in training. name (str): The name of the model for artifact storing. + random_seed (int): Seed for random number generation to ensure reproducible results. + val_ratio (float): Proportion of the dataset used for validation, between 0 and 1. + save_checkpoints (bool): If true, store checkpoints. """ super().__init__( - window_size, stride, batch_size, lr, num_epochs, device, verbose, name + window_size, stride, batch_size, lr, num_epochs, device, verbose, name, random_seed, val_ratio, save_checkpoints ) + self.val_metrics = True self.hidden_dim = hidden_dim self.loss_array = [] @@ -416,13 +423,13 @@

Source code for ice.remaining_useful_life_estimation.models.mlp

**{"hidden_dim": ["MODEL", "HIDDEN_DIM"]} ) - def _create_model(self, df: DataFrame, target: Series): - num_sensors = df.shape[1] - + def _create_model(self, input_dim: int, output_dim: int): self.model = nn.Sequential( + nn.Dropout(0.5), nn.Flatten(), - nn.Linear(num_sensors * self.window_size, self.hidden_dim), + nn.Linear(input_dim * self.window_size, self.hidden_dim), nn.ReLU(), + nn.Dropout(0.5), nn.Linear(self.hidden_dim, 1), nn.Flatten(start_dim=0), )
diff --git a/docs/_modules/index.html b/docs/_modules/index.html index 962bcad..e9571bf 100644 --- a/docs/_modules/index.html +++ b/docs/_modules/index.html @@ -367,6 +367,9 @@

All modules for which code is available

  • ice.anomaly_detection.metrics
  • ice.anomaly_detection.models.autoencoder
  • ice.anomaly_detection.models.base
  • +
  • ice.anomaly_detection.models.gnn
  • +
  • ice.anomaly_detection.models.stgat
  • +
  • ice.anomaly_detection.models.transformer
  • ice.anomaly_detection.utils
  • ice.base
  • ice.configs
  • @@ -384,6 +387,7 @@

    All modules for which code is available

  • ice.remaining_useful_life_estimation.datasets
  • ice.remaining_useful_life_estimation.metrics
  • ice.remaining_useful_life_estimation.models.base
  • +
  • ice.remaining_useful_life_estimation.models.lstm
  • ice.remaining_useful_life_estimation.models.mlp
  • ice.remaining_useful_life_estimation.utils
  • diff --git a/docs/_sources/advanced/index.rst.txt b/docs/_sources/advanced/index.rst.txt index 241fa75..16b47c1 100644 --- a/docs/_sources/advanced/index.rst.txt +++ b/docs/_sources/advanced/index.rst.txt @@ -4,4 +4,7 @@ Advanced materials ################## -2nd project stage problem \ No newline at end of file +.. toctree:: + :maxdepth: 2 + + optimization_tutorial \ No newline at end of file diff --git a/docs/_sources/advanced/optimization_tutorial.ipynb.txt b/docs/_sources/advanced/optimization_tutorial.ipynb.txt new file mode 100644 index 0000000..541fbc1 --- /dev/null +++ b/docs/_sources/advanced/optimization_tutorial.ipynb.txt @@ -0,0 +1,881 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "5908e829", + "metadata": {}, + "source": [ + "# Optimization tutorial" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "7e7ea27e-aca8-4bdc-bcdb-dda20d6ac045", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\user\\conda\\envs\\ice_testing\\Lib\\site-packages\\tqdm\\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + } + ], + "source": [ + "from ice.remaining_useful_life_estimation.datasets import RulCmapss\n", + "from ice.remaining_useful_life_estimation.models import MLP" + ] + }, + { + "cell_type": "markdown", + "id": "f9f612b9-f990-40f8-9191-af341827f7d9", + "metadata": {}, + "source": [ + "Create the MLP model and dataset class." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "81f891c7-de45-448f-a65b-806f2446e6e5", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Reading data/C-MAPSS/fd1_train.csv: 100%|██████████| 20631/20631 [00:00<00:00, 517496.66it/s]\n", + "Reading data/C-MAPSS/fd2_train.csv: 100%|██████████| 53759/53759 [00:00<00:00, 539376.73it/s]\n", + "Reading data/C-MAPSS/fd3_train.csv: 100%|██████████| 24720/24720 [00:00<00:00, 506176.62it/s]\n", + "Reading data/C-MAPSS/fd4_train.csv: 100%|██████████| 61249/61249 [00:00<00:00, 539069.75it/s]\n", + "Reading data/C-MAPSS/fd1_train.csv: 100%|██████████| 20631/20631 [00:00<00:00, 544734.35it/s]\n", + "Reading data/C-MAPSS/fd2_train.csv: 100%|██████████| 53759/53759 [00:00<00:00, 481589.37it/s]\n", + "Reading data/C-MAPSS/fd3_train.csv: 100%|██████████| 24720/24720 [00:00<00:00, 427933.68it/s]\n", + "Reading data/C-MAPSS/fd4_train.csv: 100%|██████████| 61249/61249 [00:00<00:00, 546792.80it/s]\n", + "Reading data/C-MAPSS/fd1_test.csv: 100%|██████████| 13097/13097 [00:00<00:00, 505412.69it/s]\n", + "Reading data/C-MAPSS/fd2_test.csv: 100%|██████████| 33991/33991 [00:00<00:00, 478933.98it/s]\n", + "Reading data/C-MAPSS/fd3_test.csv: 100%|██████████| 16598/16598 [00:00<00:00, 520419.66it/s]\n", + "Reading data/C-MAPSS/fd4_test.csv: 100%|██████████| 41214/41214 [00:00<00:00, 537036.66it/s]\n", + "Reading data/C-MAPSS/fd1_test.csv: 100%|██████████| 13097/13097 [00:00<00:00, 515225.24it/s]\n", + "Reading data/C-MAPSS/fd2_test.csv: 100%|██████████| 33991/33991 [00:00<00:00, 520644.44it/s]\n", + "Reading data/C-MAPSS/fd3_test.csv: 100%|██████████| 16598/16598 [00:00<00:00, 489809.10it/s]\n", + "Reading data/C-MAPSS/fd4_test.csv: 100%|██████████| 41214/41214 [00:00<00:00, 537023.31it/s]\n" + ] + } + ], + "source": [ + "dataset_class = RulCmapss()\n", + "data, target = dataset_class.df[0], dataset_class.target[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "6fc9029e-7ce9-4cd8-9353-087b66556b17", + "metadata": {}, + "outputs": [], + "source": [ + "model = MLP(device=\"cuda\")" + ] + }, + { + "cell_type": "markdown", + "id": "f8ff1a72-19f4-4389-9362-35a80b8fb851", + "metadata": {}, + "source": [ + "Optimization **without changing the complexity** of the training process. Tune the lr of the training procedure using validation loss as optimization target" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "c9e23868-09cb-4693-ad67-f1104245b7df", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[I 2024-08-13 09:53:33,784] A new study created in memory with name: /parameter_lr study\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "trial step with lr = 0.00018951382914416393\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Creating sequence of samples: 100%|██████████| 100/100 [00:00<00:00, 33442.07it/s]\n", + "Epochs ...: 0%| | 0/5 [00:00\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    FaultTPRFPR
    000.96750.0000
    110.97380.0000
    230.96430.0000
    340.95840.0000
    450.97310.0000
    560.96790.0000
    670.96910.0000
    790.96510.0000
    8100.97880.0000
    9110.95260.0000
    10120.94180.0001
    11130.97800.0000
    12150.97520.0000
    13160.96080.0000
    14170.93570.0000
    15180.97170.0000
    16190.94820.0000
    \n", + "
    " + ], + "text/plain": [ + " Fault TPR FPR\n", + "0 0 0.9675 0.0000\n", + "1 1 0.9738 0.0000\n", + "2 3 0.9643 0.0000\n", + "3 4 0.9584 0.0000\n", + "4 5 0.9731 0.0000\n", + "5 6 0.9679 0.0000\n", + "6 7 0.9691 0.0000\n", + "7 9 0.9651 0.0000\n", + "8 10 0.9788 0.0000\n", + "9 11 0.9526 0.0000\n", + "10 12 0.9418 0.0001\n", + "11 13 0.9780 0.0000\n", + "12 15 0.9752 0.0000\n", + "13 16 0.9608 0.0000\n", + "14 17 0.9357 0.0000\n", + "15 18 0.9717 0.0000\n", + "16 19 0.9482 0.0000" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "idx = np.array([1, 2, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20]) - 1\n", + "pd.DataFrame({\n", + " 'Fault': idx,\n", + " 'TPR': np.array(metrics['true_positive_rate'])[idx],\n", + " 'FPR': np.array(metrics['false_positive_rate'])[idx],\n", + "}).round(4)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "2ad2b5f0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Average TPR: 0.96\n" + ] + } + ], + "source": [ + "print(f'Average TPR: {np.array(metrics[\"true_positive_rate\"])[idx].mean():.2f}')" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "c3a334ba", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "96.75\n", + "97.38\n", + "96.43\n", + "95.84\n", + "97.31\n", + "96.79\n", + "96.91\n", + "96.51\n", + "97.88\n", + "95.26\n", + "94.18\n", + "97.80\n", + "97.52\n", + "96.08\n", + "93.57\n", + "97.17\n", + "94.82\n" + ] + } + ], + "source": [ + "for i in np.array(metrics[\"true_positive_rate\"])[idx]*100:\n", + " print(f'{i:.2f}')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "878cf22c", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/_sources/benchmark/hi_sota.ipynb.txt b/docs/_sources/benchmark/hi_sota.ipynb.txt new file mode 100644 index 0000000..c0aa68b --- /dev/null +++ b/docs/_sources/benchmark/hi_sota.ipynb.txt @@ -0,0 +1,338 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f2da72a3-830f-4a34-b767-230ed0dbf154", + "metadata": {}, + "source": [ + "# Results of HI estimation using Stacked LSTM" + ] + }, + { + "cell_type": "markdown", + "id": "e3de787a-3db3-47c0-a1c6-a2b36cc6586f", + "metadata": {}, + "source": [ + "This notebook presents experimental results of hi estimation on the Milling dataset using the model MLP-256.\n", + "\n", + "Importing libraries." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "0d2bf80e-d11f-4c3d-ac75-e4f0cfd418f6", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\user\\conda\\envs\\ice_testing\\Lib\\site-packages\\tqdm\\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + } + ], + "source": [ + "from ice.health_index_estimation.datasets import Milling\n", + "from ice.health_index_estimation.models import MLP, TCM, IE_SBiGRU, Stacked_LSTM\n", + "\n", + "import pandas as pd\n", + "import numpy as np\n", + "import torch\n", + "from tqdm.auto import trange\n", + " " + ] + }, + { + "cell_type": "markdown", + "id": "41bd9f60-51bf-4bb8-adc8-33a6abf923a1", + "metadata": {}, + "source": [ + "Initializing model class and train/test data split" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "814ba92e-e394-49a4-ac06-7b68361cf078", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Reading data/milling/case_1.csv: 100%|██████████| 153000/153000 [00:00<00:00, 1268689.48it/s]\n", + "Reading data/milling/case_2.csv: 100%|██████████| 117000/117000 [00:00<00:00, 1248873.41it/s]\n", + "Reading data/milling/case_3.csv: 100%|██████████| 126000/126000 [00:00<00:00, 1276983.81it/s]\n", + "Reading data/milling/case_4.csv: 100%|██████████| 63000/63000 [00:00<00:00, 1374151.83it/s]\n", + "Reading data/milling/case_5.csv: 100%|██████████| 54000/54000 [00:00<00:00, 1290003.79it/s]\n", + "Reading data/milling/case_6.csv: 100%|██████████| 9000/9000 [00:00<00:00, 1003395.34it/s]\n", + "Reading data/milling/case_7.csv: 100%|██████████| 72000/72000 [00:00<00:00, 1245529.71it/s]\n", + "Reading data/milling/case_8.csv: 100%|██████████| 54000/54000 [00:00<00:00, 1321487.68it/s]\n", + "Reading data/milling/case_9.csv: 100%|██████████| 81000/81000 [00:00<00:00, 1377467.66it/s]\n", + "Reading data/milling/case_10.csv: 100%|██████████| 90000/90000 [00:00<00:00, 1347769.63it/s]\n", + "Reading data/milling/case_11.csv: 100%|██████████| 207000/207000 [00:00<00:00, 1180064.87it/s]\n", + "Reading data/milling/case_12.csv: 100%|██████████| 126000/126000 [00:00<00:00, 1276980.73it/s]\n", + "Reading data/milling/case_13.csv: 100%|██████████| 135000/135000 [00:00<00:00, 1242669.46it/s]\n", + "Reading data/milling/case_14.csv: 100%|██████████| 81000/81000 [00:00<00:00, 1310826.20it/s]\n", + "Reading data/milling/case_15.csv: 100%|██████████| 63000/63000 [00:00<00:00, 1316886.37it/s]\n", + "Reading data/milling/case_16.csv: 100%|██████████| 18000/18000 [00:00<00:00, 1128731.62it/s]\n", + "C:\\Users\\user\\conda\\envs\\ice_testing\\Lib\\site-packages\\scipy\\interpolate\\_interpolate.py:479: RuntimeWarning: invalid value encountered in divide\n", + " slope = (y_hi - y_lo) / (x_hi - x_lo)[:, None]\n" + ] + } + ], + "source": [ + "dataset_class = Milling()\n", + "\n", + "data, target = pd.concat(dataset_class.df), pd.concat(dataset_class.target) \n", + "test_data, test_target = dataset_class.test[0], dataset_class.test_target[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "75a22b4c-5b1c-4ce0-b74e-6886d1c61c90", + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.preprocessing import StandardScaler, MinMaxScaler\n", + "import pandas as pd \n", + "\n", + "scaler = MinMaxScaler()\n", + "trainer_data = scaler.fit_transform(data)\n", + "tester_data = scaler.transform(test_data)\n", + "\n", + "trainer_data = pd.DataFrame(trainer_data, index=data.index, columns=data.columns)\n", + "tester_data = pd.DataFrame(tester_data, index=test_data.index, columns=test_data.columns)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "049500f5-24a0-4076-a2eb-2e15970e3abb", + "metadata": {}, + "outputs": [], + "source": [ + "# path_to_tar = \"hi_sota/\"" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "ac338ba4-ab10-41cc-916b-0413bed0d1c6", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "model_class = Stacked_LSTM(\n", + " window_size=64,\n", + " stride=1024, # 1024\n", + " batch_size=253, # 256\n", + " lr= 0.0031789041005068647, # 0.0004999805761074147,\n", + " num_epochs=55,\n", + " verbose=True,\n", + " device='cuda'\n", + " )\n", + "# model_class.fit(trainer_data, target)\n", + "model_class.load_checkpoint(path_to_tar + \"stack_sota.tar\")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "1512dcc2-1765-42f6-ab71-b8a44aa699df", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Creating sequence of samples: 100%|██████████| 14/14 [00:00<00:00, 2809.31it/s]\n", + " \r" + ] + }, + { + "data": { + "text/plain": [ + "{'mse': 0.0022332468596409335, 'rmse': 0.047257241346072384}" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model_class.evaluate(tester_data, test_target)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "defe310c-5d1e-412d-b68d-447a975ef937", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b58a2a2b-9b73-4ac8-959e-4f93db8cd8eb", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "e7638bc7-d161-4266-b2d1-aa3545856853", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "model_class = TCM(\n", + " window_size=64,\n", + " stride=1024, # 1024\n", + " batch_size=253, # 256\n", + " lr= 0.0031789041005068647, # 0.0004999805761074147,\n", + " num_epochs=55,\n", + " verbose=True,\n", + " device='cuda'\n", + " )\n", + "# model_class.fit(trainer_data, target)\n", + "model_class.load_checkpoint(path_to_tar + \"TCM_sota.tar\")" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "550c5609-a0ec-48d3-9149-a4de69ba8368", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Creating sequence of samples: 100%|██████████| 14/14 [00:00<00:00, 3511.98it/s]\n", + " \r" + ] + }, + { + "data": { + "text/plain": [ + "{'mse': 0.004014168163365719, 'rmse': 0.06335746335962102}" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model_class.evaluate(tester_data, test_target)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ede9a8c3-27e5-42df-980e-bcdb1ddcec73", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e1ee17ee-09a8-4e7e-a81d-bea529af3f7f", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "767c37e2-1750-46d5-9cd7-f628e7322305", + "metadata": {}, + "source": [ + "Training and testing with difference random seed for uncertainty estimation" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "1c5e6783-49df-46b5-86a0-6f09ee501d0e", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "model_class = IE_SBiGRU(\n", + " window_size=64,\n", + " stride=1024, # 1024\n", + " batch_size=253, # 256\n", + " lr= 0.0011, # 0.0004999805761074147,\n", + " num_epochs=35,\n", + " verbose=True,\n", + " device='cuda'\n", + " )\n", + "# model_class.fit(trainer_data, target)\n", + "model_class.load_checkpoint(path_to_tar + \"IE_SBiGRU_sota.tar\")" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "6425462a-14a5-4580-b082-92e9165d8984", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Creating sequence of samples: 100%|██████████| 14/14 [00:00<00:00, 2341.13it/s]\n", + " \r" + ] + }, + { + "data": { + "text/plain": [ + "{'mse': 0.004956771691496658, 'rmse': 0.07040434426579555}" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model_class.evaluate(tester_data, test_target)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/_sources/benchmark/index.rst.txt b/docs/_sources/benchmark/index.rst.txt index e8a7f30..6cae700 100644 --- a/docs/_sources/benchmark/index.rst.txt +++ b/docs/_sources/benchmark/index.rst.txt @@ -9,6 +9,12 @@ Benchmarking :caption: Contents: fd_benchmark_mlp_256 + fd_benchmark_tcn ad_benchmark_autoencodermlp_256 + ad_benchmark_transformer + ad_benchmark_stgat + ad_benchmark_gnn rul_benchmark_lstm_256 - hi_benchmark_mlp_256 \ No newline at end of file + rul_sota + hi_benchmark_mlp_256 + hi_sota \ No newline at end of file diff --git a/docs/_sources/benchmark/rul_sota.ipynb.txt b/docs/_sources/benchmark/rul_sota.ipynb.txt new file mode 100644 index 0000000..4a7e0a9 --- /dev/null +++ b/docs/_sources/benchmark/rul_sota.ipynb.txt @@ -0,0 +1,187 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f2da72a3-830f-4a34-b767-230ed0dbf154", + "metadata": {}, + "source": [ + "# Results of RUL estimation using IR" + ] + }, + { + "cell_type": "markdown", + "id": "e3de787a-3db3-47c0-a1c6-a2b36cc6586f", + "metadata": {}, + "source": [ + "This notebook presents experimental results of rul estimation on the CMAPSS dataset using the model lstm-256.\n", + "\n", + "Importing libraries." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "0d2bf80e-d11f-4c3d-ac75-e4f0cfd418f6", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\user\\conda\\envs\\ice_testing\\Lib\\site-packages\\tqdm\\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + } + ], + "source": [ + "from ice.remaining_useful_life_estimation.datasets import RulCmapss\n", + "from ice.remaining_useful_life_estimation.models import IR \n", + "\n", + "import pandas as pd" + ] + }, + { + "cell_type": "markdown", + "id": "41bd9f60-51bf-4bb8-adc8-33a6abf923a1", + "metadata": {}, + "source": [ + "Initializing model class and train/test data split for fd001 subdataset" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "814ba92e-e394-49a4-ac06-7b68361cf078", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Reading data/C-MAPSS/fd1_train.csv: 100%|██████████| 20631/20631 [00:00<00:00, 504872.87it/s]\n", + "Reading data/C-MAPSS/fd2_train.csv: 100%|██████████| 53759/53759 [00:00<00:00, 533656.45it/s]\n", + "Reading data/C-MAPSS/fd3_train.csv: 100%|██████████| 24720/24720 [00:00<00:00, 496051.49it/s]\n", + "Reading data/C-MAPSS/fd4_train.csv: 100%|██████████| 61249/61249 [00:00<00:00, 532245.75it/s]\n", + "Reading data/C-MAPSS/fd1_train.csv: 100%|██████████| 20631/20631 [00:00<00:00, 547602.44it/s]\n", + "Reading data/C-MAPSS/fd2_train.csv: 100%|██████████| 53759/53759 [00:00<00:00, 528810.42it/s]\n", + "Reading data/C-MAPSS/fd3_train.csv: 100%|██████████| 24720/24720 [00:00<00:00, 496134.57it/s]\n", + "Reading data/C-MAPSS/fd4_train.csv: 100%|██████████| 61249/61249 [00:00<00:00, 529770.68it/s]\n", + "Reading data/C-MAPSS/fd1_test.csv: 100%|██████████| 13097/13097 [00:00<00:00, 486699.50it/s]\n", + "Reading data/C-MAPSS/fd2_test.csv: 100%|██████████| 33991/33991 [00:00<00:00, 501537.62it/s]\n", + "Reading data/C-MAPSS/fd3_test.csv: 100%|██████████| 16598/16598 [00:00<00:00, 512334.66it/s]\n", + "Reading data/C-MAPSS/fd4_test.csv: 100%|██████████| 41214/41214 [00:00<00:00, 523435.48it/s]\n", + "Reading data/C-MAPSS/fd1_test.csv: 100%|██████████| 13097/13097 [00:00<00:00, 474171.77it/s]\n", + "Reading data/C-MAPSS/fd2_test.csv: 100%|██████████| 33991/33991 [00:00<00:00, 501537.62it/s]\n", + "Reading data/C-MAPSS/fd3_test.csv: 100%|██████████| 16598/16598 [00:00<00:00, 520419.66it/s]\n", + "Reading data/C-MAPSS/fd4_test.csv: 100%|██████████| 41214/41214 [00:00<00:00, 519167.37it/s]\n" + ] + } + ], + "source": [ + "dataset_class = RulCmapss()\n", + "\n", + "data, target = dataset_class.df[0], dataset_class.target[0]\n", + "test_data, test_target = dataset_class.test[0], dataset_class.test_target[0] " + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "717c0b98-a3cb-4cef-bf11-b9274617eddc", + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.preprocessing import StandardScaler, MinMaxScaler\n", + "import pandas as pd \n", + "\n", + "scaler = MinMaxScaler()\n", + "trainer_data = scaler.fit_transform(data)\n", + "tester_data = scaler.transform(test_data)\n", + "\n", + "trainer_data = pd.DataFrame(trainer_data, index=data.index, columns=data.columns)\n", + "tester_data = pd.DataFrame(tester_data, index=test_data.index, columns=test_data.columns)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "767c37e2-1750-46d5-9cd7-f628e7322305", + "metadata": {}, + "source": [ + "Training and testing with difference random seed for uncertainty estimation" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "f9bd5cb4-3cbd-48f2-bb70-8154f2a8e051", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\user\\conda\\envs\\ice_testing\\Lib\\site-packages\\torch\\nn\\modules\\transformer.py:306: UserWarning: enable_nested_tensor is True, but self.use_nested_tensor is False because encoder_layer.activation_relu_or_gelu was not True\n", + " warnings.warn(f\"enable_nested_tensor is True, but self.use_nested_tensor is False because {why_not_sparsity_fast_path}\")\n" + ] + } + ], + "source": [ + "model_class = IR()\n", + "model_class.load_checkpoint(\"rul_sota.tar\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "15689271-81f5-4197-934a-7ac71c32f057", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Creating sequence of samples: 100%|██████████| 100/100 [00:00<00:00, 11148.24it/s]\n", + " \r" + ] + }, + { + "data": { + "text/plain": [ + "{'rmse': 11.99217470692219, 'cmapss_score': 25394.12755711561}" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model_class.evaluate(tester_data, test_target)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/_sources/reference/ice.anomaly_detection.models.rst.txt b/docs/_sources/reference/ice.anomaly_detection.models.rst.txt index a602716..a7bd8f1 100644 --- a/docs/_sources/reference/ice.anomaly_detection.models.rst.txt +++ b/docs/_sources/reference/ice.anomaly_detection.models.rst.txt @@ -6,15 +6,32 @@ BaseAnomalyDetection .. automodule:: ice.anomaly_detection.models.base :members: - :undoc-members: :show-inheritance: AutoEncoderMLP -------------- -.. automodule:: ice.anomaly_detection.models.autoencoder +.. autoclass:: ice.anomaly_detection.models.autoencoder.AutoEncoderMLP :members: - :undoc-members: :show-inheritance: +AnomalyTransformer +------------------ +.. autoclass:: ice.anomaly_detection.models.transformer.AnomalyTransformer + :members: + :show-inheritance: + +STGAT-MAD +------------------ + +.. autoclass:: ice.anomaly_detection.models.stgat.STGAT_MAD + :members: + :show-inheritance: + +GSL-GNN +------------------ + +.. autoclass:: ice.anomaly_detection.models.gnn.GSL_GNN + :members: + :show-inheritance: \ No newline at end of file diff --git a/docs/_sources/reference/ice.fault_diagnosis.models.rst.txt b/docs/_sources/reference/ice.fault_diagnosis.models.rst.txt index 47e43f4..f931a78 100644 --- a/docs/_sources/reference/ice.fault_diagnosis.models.rst.txt +++ b/docs/_sources/reference/ice.fault_diagnosis.models.rst.txt @@ -6,7 +6,6 @@ BaseFaultDiagnosis .. automodule:: ice.fault_diagnosis.models.base :members: - :undoc-members: :show-inheritance: MLP @@ -14,7 +13,6 @@ MLP .. automodule:: ice.fault_diagnosis.models.mlp :members: - :undoc-members: :show-inheritance: TCN @@ -22,6 +20,5 @@ TCN .. automodule:: ice.fault_diagnosis.models.tcn :members: - :undoc-members: :show-inheritance: diff --git a/docs/_sources/reference/ice.health_index_estimation.models.rst.txt b/docs/_sources/reference/ice.health_index_estimation.models.rst.txt index 86f5ce2..ac496e1 100644 --- a/docs/_sources/reference/ice.health_index_estimation.models.rst.txt +++ b/docs/_sources/reference/ice.health_index_estimation.models.rst.txt @@ -6,14 +6,11 @@ BaseRemainingUsefulLifeEstimation .. automodule:: ice.health_index_estimation.models.base :members: - :undoc-members: :show-inheritance: MLP --- -.. automodule:: ice.health_index_estimation.models.mlp +.. autoclass:: ice.health_index_estimation.models.mlp.MLP :members: - :undoc-members: :show-inheritance: - diff --git a/docs/_sources/reference/ice.remaining_useful_life_estimation.models.rst.txt b/docs/_sources/reference/ice.remaining_useful_life_estimation.models.rst.txt index 2ce815c..61d89a0 100644 --- a/docs/_sources/reference/ice.remaining_useful_life_estimation.models.rst.txt +++ b/docs/_sources/reference/ice.remaining_useful_life_estimation.models.rst.txt @@ -6,14 +6,18 @@ BaseHealthIndexEstimation .. automodule:: ice.remaining_useful_life_estimation.models.base :members: - :undoc-members: :show-inheritance: MLP --- -.. automodule:: ice.remaining_useful_life_estimation.models.mlp +.. autoclass:: ice.remaining_useful_life_estimation.models.mlp.MLP :members: - :undoc-members: :show-inheritance: +LSTM +---- + +.. autoclass:: ice.remaining_useful_life_estimation.models.lstm.LSTM + :members: + :show-inheritance: \ No newline at end of file diff --git a/docs/_sources/reference/ice.rst.txt b/docs/_sources/reference/ice.rst.txt deleted file mode 100644 index f83e0bb..0000000 --- a/docs/_sources/reference/ice.rst.txt +++ /dev/null @@ -1,27 +0,0 @@ -ice package -=========== - -Subpackages ------------ - -.. toctree:: - :maxdepth: 4 - :hidden: - - Anomaly detection - ice.configs - ice.fault_diagnosis - ice.health_index_estimation - ice.remaining_useful_life_estimation - -Submodules ----------- - -ice.base module ---------------- - -.. automodule:: ice.base - :members: - :undoc-members: - :show-inheritance: - diff --git a/docs/_sources/reference/modules.rst.txt b/docs/_sources/reference/modules.rst.txt deleted file mode 100644 index d4b70e8..0000000 --- a/docs/_sources/reference/modules.rst.txt +++ /dev/null @@ -1,7 +0,0 @@ -ice -=== - -.. toctree:: - :maxdepth: 4 - - ice diff --git a/docs/_sources/start/datasets.rst.txt b/docs/_sources/start/datasets.rst.txt deleted file mode 100644 index b178b4f..0000000 --- a/docs/_sources/start/datasets.rst.txt +++ /dev/null @@ -1,5 +0,0 @@ -.. _datasets: - -######## -Datasets -######## \ No newline at end of file diff --git a/docs/_sources/start/tasks/task_hi.rst.txt b/docs/_sources/start/tasks/task_hi.rst.txt index 54693e1..428e3b0 100644 --- a/docs/_sources/start/tasks/task_hi.rst.txt +++ b/docs/_sources/start/tasks/task_hi.rst.txt @@ -85,14 +85,14 @@ equipment :math:`i`, :math:`N` is number of test samples. References """""""""" -The reference results of state-of-the-art papers for the original [1] -dataset are presented in table 1. +.. The reference results of state-of-the-art papers for the original [1] + dataset are presented in table 1. -Since the test dataset involves processes with unknown characteristics, it limits most -related HI-based work approaches, especially similarity-based techniques, which require -information about similar process trajectories. + Since the test dataset involves processes with unknown characteristics, it limits most + related HI-based work approaches, especially similarity-based techniques, which require + information about similar process trajectories. -.. table:: Table 1: References for C-Milling dataset, cuts ‘1’, ‘3’, ‘7’ testing, with the original dataset wear target. + .. table:: Table 1: References for C-Milling dataset, cuts ‘1’, ‘3’, ‘7’ testing, with the original dataset wear target. +--------------------------------+-----------------------+ | Model | RMSE (cycles) | diff --git a/docs/_static/hi/HI_deviation.png b/docs/_static/hi/HI_deviation.png deleted file mode 100644 index aed36e9..0000000 Binary files a/docs/_static/hi/HI_deviation.png and /dev/null differ diff --git a/docs/advanced/index.html b/docs/advanced/index.html index 4247bc8..3fe31ec 100644 --- a/docs/advanced/index.html +++ b/docs/advanced/index.html @@ -49,7 +49,7 @@ - + @@ -244,7 +244,7 @@
    -
    +
    @@ -320,6 +320,17 @@
    + + @@ -371,7 +382,11 @@

    Advanced materials#

    -

    2nd project stage problem

    +
    @@ -394,11 +409,11 @@

    next

    -

    API reference

    +

    Optimization tutorial

    diff --git a/docs/advanced/optimization_tutorial.html b/docs/advanced/optimization_tutorial.html new file mode 100644 index 0000000..530435a --- /dev/null +++ b/docs/advanced/optimization_tutorial.html @@ -0,0 +1,995 @@ + + + + + + + + + + + + Optimization tutorial — ICE documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + +
    +
    +
    +
    +
    + + + +
    +
    + +
    + + + + + + + + + + + + + +
    + +
    + + +
    +
    + +
    +
    + +
    + +
    + + + + +
    + +
    + + +
    +
    + + + + + +
    + +
    +

    Optimization tutorial#

    +
    +
    +
    from ice.remaining_useful_life_estimation.datasets import RulCmapss
    +from ice.remaining_useful_life_estimation.models import MLP
    +
    +
    +
    +
    +
    C:\Users\user\conda\envs\ice_testing\Lib\site-packages\tqdm\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
    +  from .autonotebook import tqdm as notebook_tqdm
    +
    +
    +
    +
    +

    Create the MLP model and dataset class.

    +
    +
    +
    dataset_class = RulCmapss()
    +data, target = dataset_class.df[0], dataset_class.target[0]
    +
    +
    +
    +
    +
    Reading data/C-MAPSS/fd1_train.csv: 100%|██████████| 20631/20631 [00:00<00:00, 517496.66it/s]
    +Reading data/C-MAPSS/fd2_train.csv: 100%|██████████| 53759/53759 [00:00<00:00, 539376.73it/s]
    +Reading data/C-MAPSS/fd3_train.csv: 100%|██████████| 24720/24720 [00:00<00:00, 506176.62it/s]
    +Reading data/C-MAPSS/fd4_train.csv: 100%|██████████| 61249/61249 [00:00<00:00, 539069.75it/s]
    +Reading data/C-MAPSS/fd1_train.csv: 100%|██████████| 20631/20631 [00:00<00:00, 544734.35it/s]
    +Reading data/C-MAPSS/fd2_train.csv: 100%|██████████| 53759/53759 [00:00<00:00, 481589.37it/s]
    +Reading data/C-MAPSS/fd3_train.csv: 100%|██████████| 24720/24720 [00:00<00:00, 427933.68it/s]
    +Reading data/C-MAPSS/fd4_train.csv: 100%|██████████| 61249/61249 [00:00<00:00, 546792.80it/s]
    +Reading data/C-MAPSS/fd1_test.csv: 100%|██████████| 13097/13097 [00:00<00:00, 505412.69it/s]
    +Reading data/C-MAPSS/fd2_test.csv: 100%|██████████| 33991/33991 [00:00<00:00, 478933.98it/s]
    +Reading data/C-MAPSS/fd3_test.csv: 100%|██████████| 16598/16598 [00:00<00:00, 520419.66it/s]
    +Reading data/C-MAPSS/fd4_test.csv: 100%|██████████| 41214/41214 [00:00<00:00, 537036.66it/s]
    +Reading data/C-MAPSS/fd1_test.csv: 100%|██████████| 13097/13097 [00:00<00:00, 515225.24it/s]
    +Reading data/C-MAPSS/fd2_test.csv: 100%|██████████| 33991/33991 [00:00<00:00, 520644.44it/s]
    +Reading data/C-MAPSS/fd3_test.csv: 100%|██████████| 16598/16598 [00:00<00:00, 489809.10it/s]
    +Reading data/C-MAPSS/fd4_test.csv: 100%|██████████| 41214/41214 [00:00<00:00, 537023.31it/s]
    +
    +
    +
    +
    +
    +
    +
    model = MLP(device="cuda")
    +
    +
    +
    +
    +

    Optimization without changing the complexity of the training process. Tune the lr of the training procedure using validation loss as optimization target

    +
    +
    +
    # model_class.optimize(data, target, optimize_parameter, optimize_range, direction, n_trials, epochs, optimize_metric)
    +model.optimize(data, target, optimize_parameter="lr", optimize_range=(5e-5, 1e-3), direction="minimize", n_trials=3, epochs=5) # if optimize_metric is None, than validation loss is using as optimization target
    +
    +
    +
    +
    +
    [I 2024-08-13 09:53:33,784] A new study created in memory with name: /parameter_lr study
    +
    +
    +
    trial step with lr = 0.00018951382914416393
    +
    +
    +
    Creating sequence of samples: 100%|██████████| 100/100 [00:00<00:00, 33442.07it/s]
    +Epochs ...:   0%|          | 0/5 [00:00<?, ?it/s]
    +Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  10%|█         | 24/232 [00:00<00:00, 237.23it/s]
    +Steps ...:  43%|████▎     | 99/232 [00:00<00:00, 535.34it/s]
    +Steps ...:  75%|███████▌  | 174/232 [00:00<00:00, 631.00it/s]
    +Epochs ...:  20%|██        | 1/5 [00:00<00:01,  2.31it/s]    
    +
    +
    +
    Epoch 1, Loss: 39.3309
    +Epoch 1, Validation Loss: 39.3238, Metrics: {'rmse': 50.063830627114406, 'cmapss_score': 1009001.2641988464}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  30%|██▉       | 69/232 [00:00<00:00, 686.55it/s]
    +Steps ...:  62%|██████▏   | 143/232 [00:00<00:00, 715.14it/s]
    +Steps ...:  94%|█████████▍| 218/232 [00:00<00:00, 730.32it/s]
    +Epochs ...:  40%|████      | 2/5 [00:00<00:01,  2.54it/s]    
    +
    +
    +
    Epoch 2, Loss: 36.8534
    +Epoch 2, Validation Loss: 32.2449, Metrics: {'rmse': 40.68462185124231, 'cmapss_score': 326161.11634528585}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  33%|███▎      | 76/232 [00:00<00:00, 751.21it/s]
    +Steps ...:  66%|██████▌   | 152/232 [00:00<00:00, 755.41it/s]
    +Steps ...:  98%|█████████▊| 228/232 [00:00<00:00, 756.70it/s]
    +Epochs ...:  60%|██████    | 3/5 [00:01<00:00,  2.68it/s]    
    +
    +
    +
    Epoch 3, Loss: 22.9493
    +Epoch 3, Validation Loss: 29.7487, Metrics: {'rmse': 38.11920046818511, 'cmapss_score': 251687.82706875}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  32%|███▏      | 75/232 [00:00<00:00, 745.06it/s]
    +Steps ...:  65%|██████▌   | 151/232 [00:00<00:00, 750.90it/s]
    +Steps ...:  98%|█████████▊| 227/232 [00:00<00:00, 753.53it/s]
    +Epochs ...:  80%|████████  | 4/5 [00:01<00:00,  2.74it/s]    
    +
    +
    +
    Epoch 4, Loss: 27.0963
    +Epoch 4, Validation Loss: 28.3393, Metrics: {'rmse': 36.542765927986274, 'cmapss_score': 207206.28175345066}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  32%|███▏      | 74/232 [00:00<00:00, 735.12it/s]
    +Steps ...:  65%|██████▌   | 151/232 [00:00<00:00, 752.66it/s]
    +Steps ...:  98%|█████████▊| 227/232 [00:00<00:00, 755.28it/s]
    +Epochs ...: 100%|██████████| 5/5 [00:01<00:00,  2.70it/s]    
    +[I 2024-08-13 09:53:36,351] Trial 0 finished with value: 26.89373407131288 and parameters: {'lr': 0.00018951382914416393}. Best is trial 0 with value: 26.89373407131288.
    +
    +
    +
    Epoch 5, Loss: 30.0107
    +Epoch 5, Validation Loss: 26.8937, Metrics: {'rmse': 34.96109612817986, 'cmapss_score': 171362.21049284632}
    +trial step with lr = 0.0007874022874638446
    +
    +
    +
    Creating sequence of samples: 100%|██████████| 100/100 [00:00<00:00, 12542.02it/s]
    +Epochs ...:   0%|          | 0/5 [00:00<?, ?it/s]
    +Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  17%|█▋        | 39/232 [00:00<00:00, 389.34it/s]
    +Steps ...:  48%|████▊     | 111/232 [00:00<00:00, 581.84it/s]
    +Steps ...:  81%|████████  | 187/232 [00:00<00:00, 661.02it/s]
    +Epochs ...:  20%|██        | 1/5 [00:00<00:01,  2.48it/s]    
    +
    +
    +
    Epoch 1, Loss: 32.6104
    +Epoch 1, Validation Loss: 28.4569, Metrics: {'rmse': 36.641393207296055, 'cmapss_score': 206445.81209835963}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  33%|███▎      | 76/232 [00:00<00:00, 755.00it/s]
    +Steps ...:  66%|██████▌   | 153/232 [00:00<00:00, 760.84it/s]
    +Steps ...:  99%|█████████▉| 230/232 [00:00<00:00, 752.50it/s]
    +Epochs ...:  40%|████      | 2/5 [00:00<00:01,  2.69it/s]    
    +
    +
    +
    Epoch 2, Loss: 29.5834
    +Epoch 2, Validation Loss: 22.3682, Metrics: {'rmse': 29.68363304759782, 'cmapss_score': 98649.45005642212}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  33%|███▎      | 77/232 [00:00<00:00, 764.93it/s]
    +Steps ...:  66%|██████▋   | 154/232 [00:00<00:00, 498.98it/s]
    +Steps ...:  91%|█████████ | 210/232 [00:00<00:00, 435.48it/s]
    +Epochs ...:  60%|██████    | 3/5 [00:01<00:00,  2.10it/s]    
    +
    +
    +
    Epoch 3, Loss: 17.5193
    +Epoch 3, Validation Loss: 17.9444, Metrics: {'rmse': 24.369740561776197, 'cmapss_score': 82673.16229614464}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  16%|█▌        | 37/232 [00:00<00:00, 363.96it/s]
    +Steps ...:  32%|███▏      | 74/232 [00:00<00:00, 359.81it/s]
    +Steps ...:  47%|████▋     | 110/232 [00:00<00:00, 355.65it/s]
    +Steps ...:  63%|██████▎   | 146/232 [00:00<00:00, 352.98it/s]
    +Steps ...:  79%|███████▉  | 183/232 [00:00<00:00, 357.91it/s]
    +Steps ...:  94%|█████████▍| 219/232 [00:00<00:00, 355.44it/s]
    +Epochs ...:  80%|████████  | 4/5 [00:02<00:00,  1.72it/s]    
    +
    +
    +
    Epoch 4, Loss: 16.3577
    +Epoch 4, Validation Loss: 16.1891, Metrics: {'rmse': 22.407311130072234, 'cmapss_score': 90375.15431472883}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  16%|█▌        | 36/232 [00:00<00:00, 357.63it/s]
    +Steps ...:  31%|███       | 72/232 [00:00<00:00, 343.62it/s]
    +Steps ...:  47%|████▋     | 108/232 [00:00<00:00, 346.81it/s]
    +Steps ...:  63%|██████▎   | 146/232 [00:00<00:00, 356.10it/s]
    +Steps ...:  79%|███████▉  | 183/232 [00:00<00:00, 360.17it/s]
    +Steps ...:  95%|█████████▍| 220/232 [00:00<00:00, 358.45it/s]
    +Epochs ...: 100%|██████████| 5/5 [00:02<00:00,  1.76it/s]    
    +[I 2024-08-13 09:53:39,216] Trial 1 finished with value: 16.189056094099836 and parameters: {'lr': 0.0007874022874638446}. Best is trial 1 with value: 16.189056094099836.
    +
    +
    +
    Epoch 5, Loss: 18.7968
    +Epoch 5, Validation Loss: 16.4563, Metrics: {'rmse': 22.47353109963666, 'cmapss_score': 73324.81707642713}
    +trial step with lr = 0.00012086132027556038
    +
    +
    +
    Creating sequence of samples: 100%|██████████| 100/100 [00:00<00:00, 12541.65it/s]
    +Epochs ...:   0%|          | 0/5 [00:00<?, ?it/s]
    +Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  15%|█▍        | 34/232 [00:00<00:00, 337.76it/s]
    +Steps ...:  31%|███       | 71/232 [00:00<00:00, 351.34it/s]
    +Steps ...:  46%|████▌     | 107/232 [00:00<00:00, 354.90it/s]
    +Steps ...:  62%|██████▏   | 143/232 [00:00<00:00, 356.58it/s]
    +Steps ...:  78%|███████▊  | 180/232 [00:00<00:00, 357.98it/s]
    +Steps ...:  94%|█████████▎| 217/232 [00:00<00:00, 358.82it/s]
    +Epochs ...:  20%|██        | 1/5 [00:00<00:02,  1.35it/s]    
    +
    +
    +
    Epoch 1, Loss: 42.6350
    +Epoch 1, Validation Loss: 41.5396, Metrics: {'rmse': 53.309621676839306, 'cmapss_score': 1652572.5547515503}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  16%|█▌        | 36/232 [00:00<00:00, 355.25it/s]
    +Steps ...:  31%|███       | 72/232 [00:00<00:00, 356.65it/s]
    +Steps ...:  47%|████▋     | 108/232 [00:00<00:00, 357.09it/s]
    +Steps ...:  62%|██████▏   | 144/232 [00:00<00:00, 355.91it/s]
    +Steps ...:  78%|███████▊  | 181/232 [00:00<00:00, 360.10it/s]
    +Steps ...:  94%|█████████▍| 218/232 [00:00<00:00, 359.01it/s]
    +Epochs ...:  40%|████      | 2/5 [00:01<00:02,  1.35it/s]    
    +
    +
    +
    Epoch 2, Loss: 36.4397
    +Epoch 2, Validation Loss: 37.1115, Metrics: {'rmse': 46.95681782704423, 'cmapss_score': 653010.5664245718}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  16%|█▌        | 36/232 [00:00<00:00, 351.65it/s]
    +Steps ...:  31%|███       | 72/232 [00:00<00:00, 353.10it/s]
    +Steps ...:  47%|████▋     | 109/232 [00:00<00:00, 356.46it/s]
    +Steps ...:  62%|██████▎   | 145/232 [00:00<00:00, 356.14it/s]
    +Steps ...:  78%|███████▊  | 181/232 [00:00<00:00, 355.91it/s]
    +Steps ...:  94%|█████████▎| 217/232 [00:00<00:00, 354.12it/s]
    +Epochs ...:  60%|██████    | 3/5 [00:02<00:01,  1.34it/s]    
    +
    +
    +
    Epoch 3, Loss: 25.7715
    +Epoch 3, Validation Loss: 32.9065, Metrics: {'rmse': 41.430416515203575, 'cmapss_score': 349818.50039921864}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  16%|█▌        | 37/232 [00:00<00:00, 360.43it/s]
    +Steps ...:  32%|███▏      | 74/232 [00:00<00:00, 359.15it/s]
    +Steps ...:  48%|████▊     | 111/232 [00:00<00:00, 359.73it/s]
    +Steps ...:  64%|██████▍   | 148/232 [00:00<00:00, 360.01it/s]
    +Steps ...:  80%|███████▉  | 185/232 [00:00<00:00, 359.48it/s]
    +Steps ...:  95%|█████████▌| 221/232 [00:00<00:00, 356.30it/s]
    +Epochs ...:  80%|████████  | 4/5 [00:02<00:00,  1.35it/s]    
    +
    +
    +
    Epoch 4, Loss: 29.5199
    +Epoch 4, Validation Loss: 30.6848, Metrics: {'rmse': 39.035223216989905, 'cmapss_score': 274871.78833234054}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  16%|█▌        | 36/232 [00:00<00:00, 350.68it/s]
    +Steps ...:  31%|███       | 72/232 [00:00<00:00, 352.70it/s]
    +Steps ...:  47%|████▋     | 108/232 [00:00<00:00, 348.67it/s]
    +Steps ...:  62%|██████▏   | 143/232 [00:00<00:00, 332.92it/s]
    +Steps ...:  77%|███████▋  | 178/232 [00:00<00:00, 338.04it/s]
    +Steps ...:  92%|█████████▏| 214/232 [00:00<00:00, 343.43it/s]
    +Epochs ...: 100%|██████████| 5/5 [00:03<00:00,  1.34it/s]    
    +[I 2024-08-13 09:53:42,980] Trial 2 finished with value: 29.60851450664241 and parameters: {'lr': 0.00012086132027556038}. Best is trial 1 with value: 16.189056094099836.
    +
    +
    +
    Epoch 5, Loss: 33.5629
    +Epoch 5, Validation Loss: 29.6085, Metrics: {'rmse': 37.93360429205696, 'cmapss_score': 242353.786303807}
    +Best hyperparameters: {'lr': 0.0007874022874638446}
    +Best trial: FrozenTrial(number=1, state=1, values=[16.189056094099836], datetime_start=datetime.datetime(2024, 8, 13, 9, 53, 36, 351082), datetime_complete=datetime.datetime(2024, 8, 13, 9, 53, 39, 216093), params={'lr': 0.0007874022874638446}, user_attrs={}, system_attrs={}, intermediate_values={1: 28.456903271558808, 2: 22.368176297443668, 3: 17.944359942180355, 4: 16.189056094099836, 5: 16.456260332247105}, distributions={'lr': FloatDistribution(high=0.001, log=False, low=5e-05, step=None)}, trial_id=1, value=None)
    +
    +
    +
    +
    +

    Optimization with changing the complexity of the training process. Tune the MLP hidden dimension size using MSE metric as optimization target

    +
    +
    +
    # model_class.optimize(data, target, optimize_parameter, optimize_range, direction, n_trials, epochs, optimize_metric)
    +model.optimize(data, target, optimize_parameter="hidden_dim", optimize_range=(256, 1024), direction="minimize", optimize_metric="rmse", n_trials=3, epochs=5)
    +
    +
    +
    +
    +
    [I 2024-08-13 09:53:42,992] A new study created in memory with name: /parameter_hidden_dim study
    +
    +
    +
    trial step with hidden_dim = 702
    +
    +
    +
    Creating sequence of samples: 100%|██████████| 100/100 [00:00<00:00, 11148.24it/s]
    +Epochs ...:   0%|          | 0/5 [00:00<?, ?it/s]
    +Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  14%|█▍        | 32/232 [00:00<00:00, 315.23it/s]
    +Steps ...:  29%|██▉       | 67/232 [00:00<00:00, 333.10it/s]
    +Steps ...:  44%|████▍     | 102/232 [00:00<00:00, 338.76it/s]
    +Steps ...:  59%|█████▉    | 137/232 [00:00<00:00, 339.63it/s]
    +Steps ...:  74%|███████▍  | 172/232 [00:00<00:00, 340.10it/s]
    +Steps ...:  89%|████████▉ | 207/232 [00:00<00:00, 341.73it/s]
    +Epochs ...:  20%|██        | 1/5 [00:00<00:03,  1.28it/s]    
    +
    +
    +
    Epoch 1, Loss: 41.7009
    +Epoch 1, Validation Loss: 41.0446, Metrics: {'rmse': 52.46324288978529, 'cmapss_score': 1459642.2102222845}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  16%|█▌        | 36/232 [00:00<00:00, 350.68it/s]
    +Steps ...:  31%|███       | 72/232 [00:00<00:00, 354.74it/s]
    +Steps ...:  47%|████▋     | 108/232 [00:00<00:00, 354.46it/s]
    +Steps ...:  62%|██████▏   | 144/232 [00:00<00:00, 354.32it/s]
    +Steps ...:  78%|███████▊  | 181/232 [00:00<00:00, 357.14it/s]
    +Steps ...:  94%|█████████▎| 217/232 [00:00<00:00, 354.29it/s]
    +Epochs ...:  40%|████      | 2/5 [00:01<00:02,  1.31it/s]    
    +
    +
    +
    Epoch 2, Loss: 34.5571
    +Epoch 2, Validation Loss: 35.5294, Metrics: {'rmse': 44.69688917194367, 'cmapss_score': 487095.93532787054}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  14%|█▍        | 33/232 [00:00<00:00, 328.99it/s]
    +Steps ...:  29%|██▉       | 67/232 [00:00<00:00, 335.00it/s]
    +Steps ...:  44%|████▍     | 103/232 [00:00<00:00, 342.81it/s]
    +Steps ...:  59%|█████▉    | 138/232 [00:00<00:00, 342.07it/s]
    +Steps ...:  75%|███████▍  | 173/232 [00:00<00:00, 340.46it/s]
    +Steps ...:  90%|████████▉ | 208/232 [00:00<00:00, 342.89it/s]
    +Epochs ...:  60%|██████    | 3/5 [00:02<00:01,  1.30it/s]    
    +
    +
    +
    Epoch 3, Loss: 24.0595
    +Epoch 3, Validation Loss: 31.7725, Metrics: {'rmse': 40.124605880566875, 'cmapss_score': 305081.3116466362}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  15%|█▌        | 35/232 [00:00<00:00, 344.29it/s]
    +Steps ...:  30%|███       | 70/232 [00:00<00:00, 344.29it/s]
    +Steps ...:  46%|████▌     | 106/232 [00:00<00:00, 347.96it/s]
    +Steps ...:  61%|██████    | 142/232 [00:00<00:00, 350.98it/s]
    +Steps ...:  77%|███████▋  | 178/232 [00:00<00:00, 350.24it/s]
    +Steps ...:  92%|█████████▏| 214/232 [00:00<00:00, 349.78it/s]
    +Epochs ...:  80%|████████  | 4/5 [00:03<00:00,  1.30it/s]    
    +
    +
    +
    Epoch 4, Loss: 27.7565
    +Epoch 4, Validation Loss: 29.9569, Metrics: {'rmse': 38.28838337636238, 'cmapss_score': 252440.2810893617}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  14%|█▍        | 32/232 [00:00<00:00, 314.78it/s]
    +Steps ...:  28%|██▊       | 66/232 [00:00<00:00, 324.48it/s]
    +Steps ...:  44%|████▍     | 102/232 [00:00<00:00, 337.97it/s]
    +Steps ...:  59%|█████▊    | 136/232 [00:00<00:00, 338.51it/s]
    +Steps ...:  73%|███████▎  | 170/232 [00:00<00:00, 330.41it/s]
    +Steps ...:  88%|████████▊ | 204/232 [00:00<00:00, 324.28it/s]
    +Epochs ...: 100%|██████████| 5/5 [00:03<00:00,  1.29it/s]    
    +[I 2024-08-13 09:53:46,884] Trial 0 finished with value: 37.12774637917532 and parameters: {'hidden_dim': 702}. Best is trial 0 with value: 37.12774637917532.
    +
    +
    +
    Epoch 5, Loss: 31.4343
    +Epoch 5, Validation Loss: 28.8321, Metrics: {'rmse': 37.12774637917532, 'cmapss_score': 219477.3266793877}
    +trial step with hidden_dim = 662
    +
    +
    +
    Creating sequence of samples: 100%|██████████| 100/100 [00:00<00:00, 12542.40it/s]
    +Epochs ...:   0%|          | 0/5 [00:00<?, ?it/s]
    +Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  15%|█▍        | 34/232 [00:00<00:00, 334.45it/s]
    +Steps ...:  30%|██▉       | 69/232 [00:00<00:00, 342.21it/s]
    +Steps ...:  45%|████▍     | 104/232 [00:00<00:00, 337.83it/s]
    +Steps ...:  60%|█████▉    | 139/232 [00:00<00:00, 340.97it/s]
    +Steps ...:  75%|███████▌  | 174/232 [00:00<00:00, 342.74it/s]
    +Steps ...:  90%|█████████ | 209/232 [00:00<00:00, 344.41it/s]
    +Epochs ...:  20%|██        | 1/5 [00:00<00:03,  1.26it/s]    
    +
    +
    +
    Epoch 1, Loss: 41.5648
    +Epoch 1, Validation Loss: 41.1247, Metrics: {'rmse': 52.64622625632633, 'cmapss_score': 1497278.352392366}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  14%|█▍        | 32/232 [00:00<00:00, 319.07it/s]
    +Steps ...:  28%|██▊       | 66/232 [00:00<00:00, 330.08it/s]
    +Steps ...:  44%|████▎     | 101/232 [00:00<00:00, 338.13it/s]
    +Steps ...:  59%|█████▊    | 136/232 [00:00<00:00, 341.91it/s]
    +Steps ...:  74%|███████▍  | 172/232 [00:00<00:00, 346.34it/s]
    +Steps ...:  89%|████████▉ | 207/232 [00:00<00:00, 346.80it/s]
    +Epochs ...:  40%|████      | 2/5 [00:01<00:02,  1.27it/s]    
    +
    +
    +
    Epoch 2, Loss: 37.5466
    +Epoch 2, Validation Loss: 35.6801, Metrics: {'rmse': 45.00773698916855, 'cmapss_score': 511059.8643841665}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  14%|█▍        | 33/232 [00:00<00:00, 321.46it/s]
    +Steps ...:  28%|██▊       | 66/232 [00:00<00:00, 320.47it/s]
    +Steps ...:  43%|████▎     | 99/232 [00:00<00:00, 315.95it/s]
    +Steps ...:  57%|█████▋    | 132/232 [00:00<00:00, 318.65it/s]
    +Steps ...:  71%|███████   | 165/232 [00:00<00:00, 321.90it/s]
    +Steps ...:  86%|████████▌ | 200/232 [00:00<00:00, 330.28it/s]
    +Epochs ...:  60%|██████    | 3/5 [00:02<00:01,  1.25it/s]    
    +
    +
    +
    Epoch 3, Loss: 26.5062
    +Epoch 3, Validation Loss: 31.7830, Metrics: {'rmse': 40.07700663323968, 'cmapss_score': 305080.57834935177}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  14%|█▍        | 32/232 [00:00<00:00, 318.04it/s]
    +Steps ...:  28%|██▊       | 65/232 [00:00<00:00, 323.80it/s]
    +Steps ...:  44%|████▎     | 101/232 [00:00<00:00, 337.28it/s]
    +Steps ...:  59%|█████▊    | 136/232 [00:00<00:00, 341.38it/s]
    +Steps ...:  74%|███████▎  | 171/232 [00:00<00:00, 342.43it/s]
    +Steps ...:  89%|████████▉ | 207/232 [00:00<00:00, 345.26it/s]
    +Epochs ...:  80%|████████  | 4/5 [00:03<00:00,  1.26it/s]    
    +
    +
    +
    Epoch 4, Loss: 28.9049
    +Epoch 4, Validation Loss: 29.9922, Metrics: {'rmse': 38.29525364434387, 'cmapss_score': 252989.93131717102}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  15%|█▌        | 35/232 [00:00<00:00, 345.28it/s]
    +Steps ...:  31%|███       | 71/232 [00:00<00:00, 350.49it/s]
    +Steps ...:  46%|████▌     | 107/232 [00:00<00:00, 352.15it/s]
    +Steps ...:  62%|██████▏   | 143/232 [00:00<00:00, 349.53it/s]
    +Steps ...:  77%|███████▋  | 179/232 [00:00<00:00, 351.74it/s]
    +Steps ...:  93%|█████████▎| 215/232 [00:00<00:00, 348.30it/s]
    +Epochs ...: 100%|██████████| 5/5 [00:03<00:00,  1.27it/s]    
    +[I 2024-08-13 09:53:50,841] Trial 1 finished with value: 37.207252080735245 and parameters: {'hidden_dim': 662}. Best is trial 0 with value: 37.12774637917532.
    +
    +
    +
    Epoch 5, Loss: 31.7666
    +Epoch 5, Validation Loss: 28.9132, Metrics: {'rmse': 37.207252080735245, 'cmapss_score': 221679.17640028123}
    +trial step with hidden_dim = 879
    +
    +
    +
    Creating sequence of samples: 100%|██████████| 100/100 [00:00<00:00, 11148.54it/s]
    +Epochs ...:   0%|          | 0/5 [00:00<?, ?it/s]
    +Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  15%|█▌        | 35/232 [00:00<00:00, 340.94it/s]
    +Steps ...:  31%|███       | 71/232 [00:00<00:00, 348.66it/s]
    +Steps ...:  46%|████▌     | 107/232 [00:00<00:00, 351.77it/s]
    +Steps ...:  62%|██████▏   | 143/232 [00:00<00:00, 354.07it/s]
    +Steps ...:  77%|███████▋  | 179/232 [00:00<00:00, 351.60it/s]
    +Steps ...:  93%|█████████▎| 215/232 [00:00<00:00, 353.62it/s]
    +Epochs ...:  20%|██        | 1/5 [00:00<00:03,  1.32it/s]    
    +
    +
    +
    Epoch 1, Loss: 40.2073
    +Epoch 1, Validation Loss: 40.6210, Metrics: {'rmse': 51.9431875404865, 'cmapss_score': 1331357.9658768093}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  16%|█▌        | 36/232 [00:00<00:00, 350.68it/s]
    +Steps ...:  31%|███       | 72/232 [00:00<00:00, 348.69it/s]
    +Steps ...:  47%|████▋     | 108/232 [00:00<00:00, 349.60it/s]
    +Steps ...:  62%|██████▎   | 145/232 [00:00<00:00, 354.45it/s]
    +Steps ...:  78%|███████▊  | 181/232 [00:00<00:00, 353.68it/s]
    +Steps ...:  94%|█████████▎| 217/232 [00:00<00:00, 352.66it/s]
    +Epochs ...:  40%|████      | 2/5 [00:01<00:02,  1.32it/s]    
    +
    +
    +
    Epoch 2, Loss: 37.4625
    +Epoch 2, Validation Loss: 34.5596, Metrics: {'rmse': 43.41147259207038, 'cmapss_score': 421283.66798380984}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  16%|█▌        | 36/232 [00:00<00:00, 358.52it/s]
    +Steps ...:  31%|███       | 72/232 [00:00<00:00, 356.73it/s]
    +Steps ...:  47%|████▋     | 109/232 [00:00<00:00, 358.43it/s]
    +Steps ...:  62%|██████▎   | 145/232 [00:00<00:00, 355.35it/s]
    +Steps ...:  78%|███████▊  | 182/232 [00:00<00:00, 358.45it/s]
    +Steps ...:  94%|█████████▍| 218/232 [00:00<00:00, 356.98it/s]
    +Epochs ...:  60%|██████    | 3/5 [00:02<00:01,  1.33it/s]    
    +
    +
    +
    Epoch 3, Loss: 23.8398
    +Epoch 3, Validation Loss: 30.9023, Metrics: {'rmse': 39.31126980464057, 'cmapss_score': 286766.446915035}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  16%|█▌        | 36/232 [00:00<00:00, 357.63it/s]
    +Steps ...:  31%|███       | 72/232 [00:00<00:00, 357.63it/s]
    +Steps ...:  47%|████▋     | 109/232 [00:00<00:00, 358.92it/s]
    +Steps ...:  62%|██████▎   | 145/232 [00:00<00:00, 358.41it/s]
    +Steps ...:  78%|███████▊  | 182/232 [00:00<00:00, 359.14it/s]
    +Steps ...:  94%|█████████▍| 218/232 [00:00<00:00, 359.17it/s]
    +Epochs ...:  80%|████████  | 4/5 [00:02<00:00,  1.34it/s]    
    +
    +
    +
    Epoch 4, Loss: 28.2913
    +Epoch 4, Validation Loss: 29.3355, Metrics: {'rmse': 37.68203820452062, 'cmapss_score': 236872.37425031906}
    +
    +
    +
    Steps ...:   0%|          | 0/232 [00:00<?, ?it/s]
    +Steps ...:  15%|█▌        | 35/232 [00:00<00:00, 347.69it/s]
    +Steps ...:  30%|███       | 70/232 [00:00<00:00, 347.69it/s]
    +Steps ...:  45%|████▌     | 105/232 [00:00<00:00, 345.31it/s]
    +Steps ...:  60%|██████    | 140/232 [00:00<00:00, 345.55it/s]
    +Steps ...:  76%|███████▌  | 176/232 [00:00<00:00, 348.00it/s]
    +Steps ...:  91%|█████████▏| 212/232 [00:00<00:00, 351.78it/s]
    +Epochs ...: 100%|██████████| 5/5 [00:03<00:00,  1.33it/s]    
    +[I 2024-08-13 09:53:54,617] Trial 2 finished with value: 36.46475764089671 and parameters: {'hidden_dim': 879}. Best is trial 2 with value: 36.46475764089671.
    +
    +
    +
    Epoch 5, Loss: 31.4287
    +Epoch 5, Validation Loss: 28.2309, Metrics: {'rmse': 36.46475764089671, 'cmapss_score': 203393.37691007284}
    +Best hyperparameters: {'hidden_dim': 879}
    +Best trial: FrozenTrial(number=2, state=1, values=[36.46475764089671], datetime_start=datetime.datetime(2024, 8, 13, 9, 53, 50, 842965), datetime_complete=datetime.datetime(2024, 8, 13, 9, 53, 54, 617905), params={'hidden_dim': 879}, user_attrs={}, system_attrs={}, intermediate_values={1: 40.62102061946218, 2: 34.55964553646925, 3: 30.902342726544635, 4: 29.335512719503264, 5: 28.230895298283276}, distributions={'hidden_dim': IntDistribution(high=1024, log=False, low=256, step=1)}, trial_id=2, value=None)
    +
    +
    +
    +
    +

    The best results are printed at the end of optimization processand saved in the outputs/task_name/traininig/param_name_optimization folder

    +
    + + +
    + + + + + + + +
    + + + +
    + + +
    +
    + +
    + +
    +
    +
    + + + + + +
    + + +
    + + \ No newline at end of file diff --git a/docs/benchmark/ad_benchmark_autoencodermlp_256.html b/docs/benchmark/ad_benchmark_autoencodermlp_256.html index fe0527a..3ec2291 100644 --- a/docs/benchmark/ad_benchmark_autoencodermlp_256.html +++ b/docs/benchmark/ad_benchmark_autoencodermlp_256.html @@ -50,7 +50,7 @@ - + @@ -477,12 +477,12 @@

    Results of anomaly detection using AutoEncoderMLP-256 @@ -396,8 +393,79 @@
    -
    -

    Datasets#

    +
    +

    Results of anomaly detection using GSL-GNN#

    +
    +
    +
    from ice.anomaly_detection.datasets import AnomalyDetectionRiethTEP
    +from ice.anomaly_detection.models import GSL_GNN
    +from sklearn.preprocessing import StandardScaler
    +import numpy as np
    +import pandas as pd
    +
    +
    +
    +
    +

    Download the dataset.

    +
    +
    +
    dataset = AnomalyDetectionRiethTEP()
    +
    +
    +
    +
    +
    +
    +

    Normalize the data.

    +
    +
    +
    scaler = StandardScaler()
    +dataset.df[dataset.train_mask] = scaler.fit_transform(dataset.df[dataset.train_mask])
    +dataset.df[dataset.test_mask] = scaler.transform(dataset.df[dataset.test_mask])
    +
    +
    +
    +
    +

    Create the GNN model.

    +
    +
    +
    model = GSL_GNN(
    +    window_size=32, 
    +    num_epochs=30, 
    +    device='cuda',
    +    verbose=True,
    +    val_ratio=0.1,
    +    save_checkpoints=True,
    +    threshold_level=0.98
    +    )
    +
    +
    +
    +
    +

    Load the checkpoint.

    +
    +
    +
    model.load_checkpoint('gnn_anomaly_detection_epoch_30.tar')
    +
    +
    +
    +
    +

    Evaluate the model on the test data.

    +
    +
    +
    metrics = model.evaluate(dataset.df[dataset.test_mask], dataset.target[dataset.test_mask])
    +metrics
    +
    +
    +
    +
    +
    {'accuracy': 0.8517518472906404,
    + 'true_positive_rate': [0.82365725],
    + 'false_positive_rate': [0.019373853211009175]}
    +
    +
    +
    +
    @@ -411,20 +479,20 @@

    previous

    -

    Installation

    +

    Results of anomaly detection using STGAT-MAD

    next

    -

    Tasks

    +

    Results of RUL estimation using lstm-256

    @@ -439,7 +507,7 @@
    @@ -591,9 +668,14 @@
  • BaseModel.evaluate()
  • BaseModel.fit()
  • BaseModel.from_config()
  • +
  • BaseModel.load_checkpoint()
  • +
  • BaseModel.model_param_estimation()
  • +
  • BaseModel.optimize()
  • BaseModel.predict()
  • +
  • BaseModel.save_checkpoint()
  • +
  • SlidingWindowDataset
  • diff --git a/docs/reference/ice.fault_diagnosis.datasets.html b/docs/reference/ice.fault_diagnosis.datasets.html index 97bb8eb..98aa1d8 100644 --- a/docs/reference/ice.fault_diagnosis.datasets.html +++ b/docs/reference/ice.fault_diagnosis.datasets.html @@ -443,6 +443,33 @@ +
    +
    +class ice.fault_diagnosis.datasets.FaultDiagnosisRiethTEP(num_chunks=None, force_download=False)[source]#
    +

    Bases: BaseDataset

    +

    Dataset of Tennessee Eastman Process dataset +Rieth, C. A., Amsel, B. D., Tran, R., & Cook, M. B. (2017). +Additional Tennessee Eastman Process Simulation Data for +Anomaly Detection Evaluation (Version V1) [Computer software]. +Harvard Dataverse. +https://doi.org/10.7910/DVN/6C3JR1.

    +
    +
    Parameters:
    +
      +
    • num_chunks (int) – If given, download only num_chunks chunks of data. +Used for testing purposes.

    • +
    • force_download (bool) – If True, download the dataset even if it exists.

    • +
    +
    +
    +
    + +

    This method has to be implemented by all children. Set name and public link.

    +
    + +
    +
    class ice.fault_diagnosis.datasets.FaultDiagnosisSmallTEP(num_chunks=None, force_download=False)[source]#
    @@ -519,6 +546,10 @@
  • FaultDiagnosisReinartzTEP.set_name_public_link()
  • +
  • FaultDiagnosisRiethTEP +
  • FaultDiagnosisSmallTEP diff --git a/docs/reference/ice.fault_diagnosis.html b/docs/reference/ice.fault_diagnosis.html index 2930859..dd93d63 100644 --- a/docs/reference/ice.fault_diagnosis.html +++ b/docs/reference/ice.fault_diagnosis.html @@ -424,6 +424,7 @@

    Fault diagnosisDatasets

  • diff --git a/docs/reference/ice.fault_diagnosis.models.html b/docs/reference/ice.fault_diagnosis.models.html index 3d82033..08d1893 100644 --- a/docs/reference/ice.fault_diagnosis.models.html +++ b/docs/reference/ice.fault_diagnosis.models.html @@ -421,50 +421,28 @@

    Fault diagnosis models

    BaseFaultDiagnosis#

    -class ice.fault_diagnosis.models.base.BaseFaultDiagnosis(window_size: int, batch_size: int, lr: float, num_epochs: int, device: str, verbose: bool, name: str)[source]#
    +class ice.fault_diagnosis.models.base.BaseFaultDiagnosis(window_size: int, stride: int, batch_size: int, lr: float, num_epochs: int, device: str, verbose: bool, name: str, random_seed: int, val_ratio: float, save_checkpoints: bool)[source]#

    Bases: BaseModel, ABC

    Base class for all fault diagnosis models.

    Parameters:
    • window_size (int) – The window size to train the model.

    • +
    • stride (int) – The time interval between first points of consecutive +sliding windows in training.

    • batch_size (int) – The batch size to train the model.

    • -
    • lr (float) – The learning rate to train the model.

    • +
    • lr (float) – The larning rate to train the model.

    • num_epochs (float) – The number of epochs to train the model.

    • device (str) – The name of a device to train the model. cpu and cuda are possible.

    • verbose (bool) – If true, show the progress bar in training.

    • name (str) – The name of the model for artifact storing.

    • +
    • random_seed (int) – Seed for random number generation to ensure reproducible results.

    • +
    • val_ratio (float) – Proportion of the dataset used for validation, between 0 and 1.

    • +
    • save_checkpoints (bool) – If true, store checkpoints.

    -
    -
    -evaluate(df: DataFrame, target: Series) dict[source]#
    -

    Evaluate the metrics: accuracy.

    -
    -
    Parameters:
    -
      -
    • df (pandas.DataFrame) – A dataframe with sensor data. Index has -two columns: run_id and sample. All other columns a value of -sensors.

    • -
    • target (pandas.Series) – A series with target values. Indes has two -columns: run_id and sample.

    • -
    -
    -
    Returns:
    -

    -
    A dictionary with metrics where keys are names of metrics and

    values are values of metrics.

    -
    -
    -

    -
    -
    Return type:
    -

    dict

    -
    -
    -
    -
    @@ -472,7 +450,7 @@

    Fault diagnosis models

    MLP#

    -class ice.fault_diagnosis.models.mlp.MLP(window_size: int, hidden_dim: int = 256, batch_size: int = 128, lr: float = 0.001, num_epochs: int = 10, device: str = 'cpu', verbose: bool = False, name: str = 'mlp_fault_diagnosis')[source]#
    +class ice.fault_diagnosis.models.mlp.MLP(window_size: int, stride: int = 1, hidden_dim: int = 256, batch_size: int = 128, lr: float = 0.001, num_epochs: int = 10, device: str = 'cpu', verbose: bool = False, name: str = 'mlp_fault_diagnosis', random_seed: int = 42, val_ratio: float = 0.15, save_checkpoints: bool = False)[source]#

    Bases: BaseFaultDiagnosis

    Multilayer Perceptron (MLP) consists of input, hidden, output layers and ReLU activation. Each sample is reshaped to a vector (B, L, C) -> (B, L * C) @@ -490,6 +468,9 @@

    Fault diagnosis modelscuda are possible.

  • verbose (bool) – If true, show the progress bar in training.

  • name (str) – The name of the model for artifact storing.

  • +
  • random_seed (int) – Seed for random number generation to ensure reproducible results.

  • +
  • val_ratio (float) – Proportion of the dataset used for validation, between 0 and 1.

  • +
  • save_checkpoints (bool) – If true, store checkpoints.

  • @@ -500,7 +481,7 @@

    Fault diagnosis models

    TCN#

    -class ice.fault_diagnosis.models.tcn.TCN(window_size: int, hidden_dim: int = 256, kernel_size: int = 5, num_layers: int = 4, dilation_base: int = 2, dropout: float = 0.2, batch_size: int = 128, lr: float = 0.001, num_epochs: int = 10, device: str = 'cpu', verbose: bool = False, name: str = 'tcn_fault_diagnosis')[source]#
    +class ice.fault_diagnosis.models.tcn.TCN(window_size: int, stride: int = 1, hidden_dim: int = 256, kernel_size: int = 5, num_layers: int = 4, dilation_base: int = 2, dropout: float = 0.2, batch_size: int = 128, lr: float = 0.001, num_epochs: int = 10, device: str = 'cpu', verbose: bool = False, name: str = 'tcn_fault_diagnosis', random_seed: int = 42, val_ratio: float = 0.15, save_checkpoints: bool = False)[source]#

    Bases: BaseFaultDiagnosis

    Temporal Convolutional Network (TCN)-based Fault Diagnosis method. The implementation is based on the paper Lomov, Ildar, et al. “Fault detection @@ -522,6 +503,9 @@

    Fault diagnosis modelscuda are possible.

  • verbose (bool) – If true, show the progress bar in training.

  • name (str) – The name of the model for artifact storing.

  • +
  • random_seed (int) – Seed for random number generation to ensure reproducible results.

  • +
  • val_ratio (float) – Proportion of the dataset used for validation, between 0 and 1.

  • +
  • save_checkpoints (bool) – If true, store checkpoints.

  • @@ -574,10 +558,7 @@

    Fault diagnosis models

    +
    +
    +ice.health_index_estimation.metrics.rmse(pred: list, target: list) float[source]#
    +

    Mean squared error between real and predicted wear.

    +
    +
    Parameters:
    +
      +
    • pred (list) – numpy prediction values.

    • +
    • target (list) – numpy target values.

    • +
    +
    +
    Returns:
    +

    rmse

    +
    +
    Return type:
    +

    float

    +
    +
    +
    + @@ -483,6 +503,7 @@
    diff --git a/docs/reference/ice.health_index_estimation.models.html b/docs/reference/ice.health_index_estimation.models.html index 306c5db..9a28761 100644 --- a/docs/reference/ice.health_index_estimation.models.html +++ b/docs/reference/ice.health_index_estimation.models.html @@ -421,14 +421,15 @@

    Remaining useful life models

    BaseRemainingUsefulLifeEstimation#

    -class ice.health_index_estimation.models.base.BaseHealthIndexEstimation(window_size: int, stride: int, batch_size: int, lr: float, num_epochs: int, device: str, verbose: bool, name: str)[source]#
    +class ice.health_index_estimation.models.base.BaseHealthIndexEstimation(window_size: int, stride: int, batch_size: int, lr: float, num_epochs: int, device: str, verbose: bool, name: str, random_seed: int, val_ratio: float, save_checkpoints: bool)[source]#

    Bases: BaseModel, ABC

    Base class for all HI diagnosis models.

    Parameters:
    • window_size (int) – The window size to train the model.

    • -
    • stride (int) – The time interval between first points of consecutive sliding windows.

    • +
    • stride (int) – The time interval between first points of consecutive +sliding windows in training.

    • batch_size (int) – The batch size to train the model.

    • lr (float) – The larning rate to train the model.

    • num_epochs (float) – The number of epochs to train the model.

    • @@ -436,44 +437,20 @@

      Remaining useful life models -
      -evaluate(df: DataFrame, target: Series) dict[source]#
      -

      Evaluate the metrics: mse.

      -
      -
      Parameters:
      -
        -
      • df (pandas.DataFrame) – A dataframe with sensor data. Index has -two columns: run_id and sample. All other columns a value of -sensors.

      • -
      • target (pandas.Series) – A series with target values. Indes has two -columns: run_id and sample.

      • -
      -
      -
      Returns:
      -

      -
      A dictionary with metrics where keys are names of metrics and

      values are values of metrics.

      -
      -
      -

      -
      -
      Return type:
      -

      dict

      -
      -
      -

    -
    -
    -

    MLP#

    +
    +

    MLP#

    -class ice.health_index_estimation.models.mlp.MLP(window_size: int = 1024, stride: int = 300, hidden_dim: int = 256, batch_size: int = 64, lr: float = 5e-05, num_epochs: int = 50, device: str = 'cpu', verbose: bool = True, name: str = 'mlp_fault_diagnosis')[source]#
    +class ice.health_index_estimation.models.mlp.MLP(window_size: int = 1024, stride: int = 300, hidden_dim: int = 256, batch_size: int = 64, lr: float = 5e-05, num_epochs: int = 50, device: str = 'cpu', verbose: bool = True, name: str = 'mlp_fault_diagnosis', random_seed: int = 42, val_ratio: float = 0.15, save_checkpoints: bool = False)[source]#

    Bases: BaseHealthIndexEstimation

    Multilayer Perceptron (MLP) consists of input, hidden, output layers and ReLU activation. Each sample is reshaped to a vector (B, L, C) -> (B, L * C) @@ -492,6 +469,9 @@

    Remaining useful life models

    +
    +
    +class ice.remaining_useful_life_estimation.datasets.RulCmapssPaper(num_chunks=None, force_download=False)[source]#
    +

    Bases: BaseDataset

    +

    Preprocessed to piece wise RUL data from the dataset: +Saxena A. et al. Damage propagation modeling for aircraft engine run-to-failure simulation +DOI: 10.1109/PHM.2008.4711414. Target is the minimum rul value for every test device.

    +
    +
    Parameters:
    +
      +
    • num_chunks (int) – If given, download only num_chunks chunks of data. +Used for testing purposes.

    • +
    • force_download (bool) – If True, download the dataset even if it exists.

    • +
    +
    +
    +
    + +

    This method has to be implemented by all children. Set name and public link.

    +
    + +
    +
    @@ -490,6 +514,10 @@
  • RulCmapss.set_name_public_link()
  • +
  • RulCmapssPaper +
  • diff --git a/docs/reference/ice.remaining_useful_life_estimation.html b/docs/reference/ice.remaining_useful_life_estimation.html index e79d574..b9d9d88 100644 --- a/docs/reference/ice.remaining_useful_life_estimation.html +++ b/docs/reference/ice.remaining_useful_life_estimation.html @@ -418,17 +418,19 @@

    Remaining useful life
  • Models
  • Datasets
  • Metrics
  • Utils
      diff --git a/docs/reference/ice.remaining_useful_life_estimation.metrics.html b/docs/reference/ice.remaining_useful_life_estimation.metrics.html index 379992a..a2889da 100644 --- a/docs/reference/ice.remaining_useful_life_estimation.metrics.html +++ b/docs/reference/ice.remaining_useful_life_estimation.metrics.html @@ -418,15 +418,19 @@

      Remaining useful life metrics#

      -
      -ice.remaining_useful_life_estimation.metrics.nonsimmetric_function(value)[source]#
      -

      Exponent calculation function depending on the relative deviation from the true value

      +
      +ice.remaining_useful_life_estimation.metrics.cmapss_score(pred: list, target: list) float[source]#
      +

      Non-simmetric metric proposed in the original dataset paper. +DOI: 10.1109/PHM.2008.4711414

      Parameters:
      -

      value (float) – division result between predicted and real values.

      +
        +
      • pred (list) – numpy prediction values.

      • +
      • target (list) – numpy target values.

      • +
      Returns:
      -

      calculation result

      +

      cmapss score function

      Return type:

      float

      @@ -435,18 +439,15 @@
      -
      -ice.remaining_useful_life_estimation.metrics.rmse(pred: list, target: list) float[source]#
      -

      Root mean squared error between real and predicted remaining useful life values.

      +
      +ice.remaining_useful_life_estimation.metrics.nonsimmetric_function(value)[source]#
      +

      Exponent calculation function depending on the relative deviation from the true value

      Parameters:
      -
        -
      • pred (list) – numpy prediction values.

      • -
      • target (list) – numpy target values.

      • -
      +

      value (float) – division result between predicted and real values.

      Returns:
      -

      rmse

      +

      calculation result

      Return type:

      float

      @@ -455,10 +456,9 @@
      -
      -ice.remaining_useful_life_estimation.metrics.score(pred: list, target: list) float[source]#
      -

      Non-simmetric metric proposed in the original dataset paper. -DOI: 10.1109/PHM.2008.4711414

      +
      +ice.remaining_useful_life_estimation.metrics.rmse(pred: list, target: list) float[source]#
      +

      Root mean squared error between real and predicted remaining useful life values.

      Parameters:
        @@ -467,7 +467,7 @@
      Returns:
      -

      cmapss score function

      +

      rmse

      Return type:

      float

      @@ -520,9 +520,9 @@
  • diff --git a/docs/reference/ice.remaining_useful_life_estimation.models.html b/docs/reference/ice.remaining_useful_life_estimation.models.html index 07b2d5b..aeba09f 100644 --- a/docs/reference/ice.remaining_useful_life_estimation.models.html +++ b/docs/reference/ice.remaining_useful_life_estimation.models.html @@ -421,70 +421,81 @@

    Health index models

    BaseHealthIndexEstimation#

    -class ice.remaining_useful_life_estimation.models.base.BaseRemainingUsefulLifeEstimation(window_size: int, stride: int, batch_size: int, lr: float, num_epochs: int, device: str, verbose: bool, name: str)[source]#
    +class ice.remaining_useful_life_estimation.models.base.BaseRemainingUsefulLifeEstimation(window_size: int, stride: int, batch_size: int, lr: float, num_epochs: int, device: str, verbose: bool, name: str, random_seed: int, val_ratio: float, save_checkpoints: bool)[source]#

    Bases: BaseModel, ABC

    Base class for all RUL models.

    Parameters:
    • window_size (int) – The window size to train the model.

    • -
    • stride (int) – The time interval between first points of consecutive sliding windows.

    • +
    • stride (int) – The time interval between first points of consecutive +sliding windows in training.

    • batch_size (int) – The batch size to train the model.

    • -
    • lr (float) – The learning rate to train the model.

    • +
    • lr (float) – The larning rate to train the model.

    • num_epochs (float) – The number of epochs to train the model.

    • device (str) – The name of a device to train the model. cpu and cuda are possible.

    • verbose (bool) – If true, show the progress bar in training.

    • name (str) – The name of the model for artifact storing.

    • +
    • random_seed (int) – Seed for random number generation to ensure reproducible results.

    • +
    • val_ratio (float) – Proportion of the dataset used for validation, between 0 and 1.

    • +
    • save_checkpoints (bool) – If true, store checkpoints.

    -
    -
    -evaluate(df: DataFrame, target: Series) dict[source]#
    -

    Evaluate the metrics: rmse, c-mapss score.

    +
    + + +
    +

    MLP#

    +
    +
    +class ice.remaining_useful_life_estimation.models.mlp.MLP(window_size: int = 32, stride: int = 1, hidden_dim: int = 512, batch_size: int = 64, lr: float = 0.0001, num_epochs: int = 15, device: str = 'cpu', verbose: bool = True, name: str = 'mlp_cmapss_rul', random_seed: int = 42, val_ratio: float = 0.15, save_checkpoints: bool = False)[source]#
    +

    Bases: BaseRemainingUsefulLifeEstimation

    +

    Multilayer Perceptron (MLP) consists of input, hidden, output layers and +ReLU activation. Each sample is reshaped to a vector (B, L, C) -> (B, L * C) +where B is the batch size, L is the sequence length, C is the number of +sensors.

    Parameters:
      -
    • df (pandas.DataFrame) – A dataframe with sensor data. Index has -two columns: run_id and sample. All other columns a value of -sensors.

    • -
    • target (pandas.Series) – A series with target values. Indes has two -columns: run_id and sample.

    • +
    • window_size (int) – The window size to train the model.

    • +
    • stride (int) – The time interval between first points of consecutive sliding windows.

    • +
    • hidden_dim (int) – The dimensionality of the hidden layer in MLP.

    • +
    • batch_size (int) – The batch size to train the model.

    • +
    • lr (float) – The larning rate to train the model.

    • +
    • num_epochs (float) – The number of epochs to train the model.

    • +
    • device (str) – The name of a device to train the model. cpu and +cuda are possible.

    • +
    • verbose (bool) – If true, show the progress bar in training.

    • +
    • name (str) – The name of the model for artifact storing.

    • +
    • random_seed (int) – Seed for random number generation to ensure reproducible results.

    • +
    • val_ratio (float) – Proportion of the dataset used for validation, between 0 and 1.

    • +
    • save_checkpoints (bool) – If true, store checkpoints.

    -
    Returns:
    -

    -
    A dictionary with metrics where keys are names of metrics and

    values are values of metrics.

    -
    -
    -

    -
    -
    Return type:
    -

    dict

    -
    -
    - -
    -

    MLP#

    +
    +

    LSTM#

    -
    -class ice.remaining_useful_life_estimation.models.mlp.MLP(window_size: int = 32, stride: int = 1, hidden_dim: int = 256, batch_size: int = 256, lr: float = 5e-05, num_epochs: int = 50, device: str = 'cpu', verbose: bool = True, name: str = 'mlp_cmapss_rul')[source]#
    +
    +class ice.remaining_useful_life_estimation.models.lstm.LSTM(window_size: int = 32, stride: int = 1, hidden_dim: int = 512, hidden_size: int = 256, num_layers: int = 2, dropout_value: float = 0.5, batch_size: int = 64, lr: float = 0.0001, num_epochs: int = 35, device: str = 'cpu', verbose: bool = True, name: str = 'mlp_cmapss_rul', random_seed: int = 42, val_ratio: float = 0.15, save_checkpoints: bool = False)[source]#

    Bases: BaseRemainingUsefulLifeEstimation

    -

    Multilayer Perceptron (MLP) consists of input, hidden, output layers and -ReLU activation. Each sample is reshaped to a vector (B, L, C) -> (B, L * C) -where B is the batch size, L is the sequence length, C is the number of -sensors.

    +

    Long short-term memory (LSTM) model consists of the classical LSTM architecture stack and +two-layer MLP with SiLU nonlinearity and dropout to make the final prediction.

    +

    Each sample is moved to LSTM and reshaped to a vector (B, L, C) -> (B, hidden_size, C) +Then the sample is reshaped to a vector (B, hidden_size, C) -> (B, hidden_size * C)

    Parameters:
    • window_size (int) – The window size to train the model.

    • stride (int) – The time interval between first points of consecutive sliding windows.

    • hidden_dim (int) – The dimensionality of the hidden layer in MLP.

    • +
    • hidden_size (int) – The number of features in the hidden state of the model.

    • +
    • num_layers (int) – The number of stacked reccurent layers of the classic LSTM architecture.

    • batch_size (int) – The batch size to train the model.

    • lr (float) – The larning rate to train the model.

    • num_epochs (float) – The number of epochs to train the model.

    • @@ -492,6 +503,9 @@

      Health index models