| """ |
| cmapss_model.py |
| =============== |
| CNN-BiLSTM-Attention model with MC Dropout for RUL prediction. |
| Used for both C-MAPSS and AGTF30 turbine blade datasets. |
| |
| Author: Mohammed Bello Sani |
| """ |
|
|
| import torch |
| import torch.nn as nn |
| import torch.nn.functional as F |
| import numpy as np |
|
|
|
|
| class CNNBiLSTMAttention(nn.Module): |
| """ |
| CNN + Bidirectional LSTM + Self-Attention + MC Dropout |
| """ |
| def __init__(self, hp): |
| super().__init__() |
| self.hp = hp |
| n_features = hp['n_features'] |
| cnn_filters = hp['cnn_filters'] |
| kernel_size = hp.get('cnn_kernel', 3) |
| lstm_hidden = hp['lstm_hidden'] |
| lstm_layers = hp['lstm_layers'] |
| fc_hidden = hp.get('fc_hidden', 64) |
| dropout = hp.get('mc_dropout', 0.5) |
|
|
| |
| cnn_layers = [] |
| in_channels = n_features |
| for i, filters in enumerate(cnn_filters): |
| cnn_layers.append(nn.Conv1d(in_channels, filters, kernel_size, padding='same')) |
| cnn_layers.append(nn.BatchNorm1d(filters)) |
| cnn_layers.append(nn.GELU()) |
| cnn_layers.append(nn.Dropout(dropout * 0.5)) |
| in_channels = filters |
| self.cnn = nn.Sequential(*cnn_layers) |
| self.cnn_out_dim = cnn_filters[-1] |
|
|
| |
| self.lstm = nn.LSTM( |
| input_size=self.cnn_out_dim, |
| hidden_size=lstm_hidden, |
| num_layers=lstm_layers, |
| batch_first=True, |
| bidirectional=True, |
| dropout=hp.get('lstm_dropout', 0.3) if lstm_layers > 1 else 0 |
| ) |
| lstm_out_dim = lstm_hidden * 2 |
|
|
| |
| self.attn_heads = hp.get('attn_heads', 4) |
| self.attn = nn.MultiheadAttention( |
| embed_dim=lstm_out_dim, |
| num_heads=self.attn_heads, |
| dropout=dropout * 0.3, |
| batch_first=True |
| ) |
| self.attn_norm = nn.LayerNorm(lstm_out_dim) |
|
|
| |
| self.fc = nn.Sequential( |
| nn.Linear(lstm_out_dim, fc_hidden), |
| nn.GELU(), |
| nn.Dropout(dropout), |
| nn.Linear(fc_hidden, 1) |
| ) |
|
|
| |
| self.dropout_rate = dropout |
|
|
| def forward(self, x): |
| |
| |
| x_cnn = x.permute(0, 2, 1) |
| x_cnn = self.cnn(x_cnn) |
| x_cnn = x_cnn.permute(0, 2, 1) |
|
|
| |
| lstm_out, _ = self.lstm(x_cnn) |
|
|
| |
| attn_out, _ = self.attn(lstm_out, lstm_out, lstm_out) |
| attn_out = self.attn_norm(attn_out + lstm_out) |
|
|
| |
| pooled = attn_out.mean(dim=1) |
|
|
| |
| out = self.fc(pooled).squeeze(-1) |
| return out |
|
|
| def predict_with_uncertainty(self, x, n_samples=100): |
| """ |
| Monte Carlo Dropout inference. |
| Returns mean and standard deviation. |
| """ |
| self.train() |
| preds = [] |
| with torch.no_grad(): |
| for _ in range(n_samples): |
| preds.append(self.forward(x).cpu().numpy()) |
| preds = np.stack(preds, axis=0) |
| mean = preds.mean(axis=0) |
| std = preds.std(axis=0) |
| return mean, std |
|
|
|
|
| |
| |
| if __name__ == '__main__': |
| print("CNNBiLSTMAttention model definition ready.") |