Back to Models

model_keras

v1.0.0
Keras

LSTM Autoencoder for sequential and temporal anomaly detection. Uses Keras LSTM layers with RepeatVector architecture, treating features as time steps for sequence reconstruction.

$ openuba install model_keras
OpenUBA
tensorflow
License: Apache-2.0
lstmautoencodersequentialtemporalkerasdeep-learning

Parameters

NameTypeDefaultDescription
epochsinteger5Number of training epochs
batch_sizeinteger32Training batch size
model.yaml
1name: model_keras
2version: 1.0.0
3runtime: tensorflow
4description: LSTM Autoencoder for sequential anomaly detection
5parameters:
6  epochs:
7    type: integer
8    default: 5
9    description: Number of training epochs
10  batch_size:
11    type: integer
12    default: 32
13    description: Training batch size
14
MODEL.py
1
2import pandas as pd
3import numpy as np
4from tensorflow import keras
5from tensorflow.keras import layers
6from typing import Dict, Any
7
8class Model:
9    def __init__(self):
10        self.model = None
11        self.input_dim = 10 
12
13    def _build_model(self, input_dim):
14        """
15        Build a Keras LSTM-based Autoencoder (treating params as sequence for demo)
16        """
17        # Reshaping input to (features, 1) for LSTM
18        model = keras.Sequential([
19            layers.Input(shape=(input_dim, 1)),
20            layers.LSTM(16, activation='relu', return_sequences=False),
21            layers.RepeatVector(input_dim),
22            layers.LSTM(16, activation='relu', return_sequences=True),
23            layers.TimeDistributed(layers.Dense(1))
24        ])
25        model.compile(optimizer='adam', loss='mae')
26        return model
27
28    def train(self, ctx) -> Dict[str, Any]:
29        """
30        Train Keras model
31        """
32        ctx.logger.info("Starting Keras LSTM training...")
33        
34        if ctx.df is None or ctx.df.empty:
35            ctx.logger.warning("No data, generating dummy")
36            X = np.random.randn(100, 10).astype(np.float32)
37        else:
38            X = ctx.df.select_dtypes(include=[np.number]).values.astype(np.float32)
39            
40        self.input_dim = X.shape[1]
41        
42        # Reshape for LSTM: [samples, time_steps, features] -> treating features as time steps here for structural demo
43        X_reshaped = X.reshape((X.shape[0], X.shape[1], 1))
44        
45        self.model = self._build_model(self.input_dim)
46        
47        history = self.model.fit(X_reshaped, X_reshaped, epochs=5, batch_size=32, verbose=0)
48        final_loss = history.history['loss'][-1]
49        
50        ctx.logger.info(f"Training completed. Final MAE: {final_loss}")
51        
52        return {
53            "status": "success",
54            "model_type": "Keras LSTM Autoencoder",
55            "final_loss": float(final_loss)
56        }
57
58    def infer(self, ctx) -> pd.DataFrame:
59        """
60        Inference
61        """
62        ctx.logger.info("Starting Keras inference...")
63        
64        if ctx.df is None or ctx.df.empty:
65            X = np.random.randn(20, self.input_dim).astype(np.float32)
66            ids = [f"user_{i}" for i in range(20)]
67        else:
68            X = ctx.df.select_dtypes(include=[np.number]).values.astype(np.float32)
69            if X.shape[1] != self.input_dim:
70                 # simple truncation/padding
71                 if X.shape[1] > self.input_dim:
72                     X = X[:, :self.input_dim]
73                 else:
74                     padding = np.zeros((X.shape[0], self.input_dim - X.shape[1]), dtype=np.float32)
75                     X = np.hstack((X, padding))
76            
77            if "entity_id" in ctx.df.columns:
78                ids = ctx.df["entity_id"].values
79            else:
80                ids = [f"entity_{i}" for i in range(len(X))]
81                
82        if self.model is None:
83             self.model = self._build_model(self.input_dim)
84
85        X_reshaped = X.reshape((X.shape[0], X.shape[1], 1))
86        reconstructions = self.model.predict(X_reshaped, verbose=0)
87        reconstructions = reconstructions.reshape((X.shape[0], X.shape[1]))
88        
89        mae = np.mean(np.abs(X - reconstructions), axis=1)
90        
91        results = []
92        for i, score in enumerate(mae):
93            risk = min(100.0, float(score) * 100)
94            results.append({
95                "entity_id": str(ids[i]),
96                "risk_score": float(risk),
97                "anomaly_type": "seq_outlier" if risk > 50 else "normal",
98                "details": {"mae": float(score)}
99            })
100            
101        return pd.DataFrame(results)
102
103    def execute(self, data=None):
104         # shim for v1
105        class MockCtx:
106            def __init__(self, d): self.df = d if d else pd.DataFrame(); self.logger = type('obj', (object,), {'info': print, 'warning': print})
107        return self.infer(MockCtx(pd.DataFrame(data) if data else None)).to_dict('records')
108