lemousehunter
v3: Add DTP + Spectral Decoupling, fix GradNorm OOM, fix _fail_job cancel
283a882
"""
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(),
}