""" MLPbest Architecture ==================== The multi-layer perceptron architecture from the ASCAD paper (Benadjila et al., 2020). Architecture: Input(700) -> 5 x Dense(200, ReLU) -> Dense(256, Softmax) Optimizer: RMSprop(lr=1e-5) """ from typing import Dict, Any import tensorflow as tf from .base import BaseModel from ..constants import MLP_DEFAULTS, NUM_CLASSES, WINDOW_SIZE class MLPBest(BaseModel): """ MLPbest architecture for ASCAD side-channel attacks. This is the best-performing MLP architecture identified in the original ASCAD paper. It consists of 5 hidden dense layers with 200 units each, followed by a softmax classification layer over 256 S-Box output classes. """ def __init__( self, input_length: int = WINDOW_SIZE, num_classes: int = NUM_CLASSES, num_hidden_layers: int = MLP_DEFAULTS["num_hidden_layers"], hidden_units: int = MLP_DEFAULTS["hidden_units"], ) -> None: """ Args: input_length: Number of time samples in the input trace. num_classes: Number of output classes. num_hidden_layers: Number of hidden dense layers. hidden_units: Number of units per hidden layer. """ super().__init__(input_shape=(input_length,), num_classes=num_classes) self.input_length = input_length self.num_hidden_layers = num_hidden_layers self.hidden_units = hidden_units def build(self) -> tf.keras.Model: """Construct the MLPbest Keras model.""" inputs = tf.keras.Input(shape=self.input_shape, name="trace_input") x = inputs for i in range(self.num_hidden_layers): x = tf.keras.layers.Dense( self.hidden_units, activation="relu", kernel_initializer="glorot_uniform", name=f"dense_{i}", )(x) outputs = tf.keras.layers.Dense( self.num_classes, activation="softmax", name="predictions", )(x) self._model = tf.keras.Model(inputs=inputs, outputs=outputs, name="MLPbest") return self._model def get_config(self) -> Dict[str, Any]: """Return architecture hyperparameters.""" return { "model_type": "mlp", "architecture": "MLPbest", "input_length": self.input_length, "num_classes": self.num_classes, "num_hidden_layers": self.num_hidden_layers, "hidden_units": self.hidden_units, "total_params": self.model.count_params(), }