Define a Model
SleePyPhases uses pyPhasesML’s ModelManager to discover, load, and save models. Models are Python classes stored in a conventional directory layout inside your project.
Directory layout
myproject/
└── models/
└── SimpleCNN/
└── SimpleCNN.py # class name must match directory name
Config keys
| Key | Type | Default | Description |
|---|---|---|---|
modelName |
str |
— | Model class name. Must match the subdirectory and class name |
modelPath |
str |
— | Path to the models/ directory (relative or absolute) |
inputShape |
list[int] |
— | [samples, channels] passed to the model’s define() method |
pretraining.pretrainedModel |
str |
— | Path to a model weights file, to use for evaluation and predict |
model |
dict |
— | Specific model configuration options |
In project.yaml
modelPath: simplecnn/models
modelName: SimpleCNN
inputShape: [806400, 1]Writing a model class
Subclass ModelTorchAdapter (for PyTorch) or ModelTFAdapter (for TensorFlow):
# simplecnn/models/SimpleCNN/SimpleCNN.py
import torch.nn as nn
from pyPhasesML.adapter.ModelTorchAdapter import ModelTorchAdapter
class SimpleCNNTorch(nn.Module):
def __init__(self, num_classes=5, num_channels=1, output_steps=840):
super().__init__()
self.cnn_layers = nn.Sequential(
nn.Conv1d(num_channels, 32, kernel_size=7, stride=1, padding=3),
nn.ReLU(),
nn.Conv1d(32, 32, kernel_size=5, stride=1, padding=2),
nn.ReLU(),
nn.Conv1d(32, 64, kernel_size=3, stride=1, padding=1),
nn.ReLU(),
nn.AdaptiveAvgPool1d(output_steps),
)
self.classifier = nn.Conv1d(64, num_classes, kernel_size=1)
def forward(self, x):
features = self.cnn_layers(x)
logits = self.classifier(features)
return logits.transpose(1, 2) # → (batch, steps, classes)
class SimpleCNN(ModelTorchAdapter):
def define(self):
"""Called once at model creation. self.inputShape is set from config."""
options = self.options # all config keys under `model` in the YAML are available here
self.model = SimpleCNNTorch(
num_classes=5,
num_channels=self.inputShape[1],
output_steps=840,
)
def prepareY(self, y, validation=False):
y = super().prepareY(y, validation)
return y.long().squeeze(2)
def getLossFunction(self):
return nn.CrossEntropyLoss(ignore_index=self.ignoreClassIndex)
def mapOutputForLoss(self, output):
return output.permute(0, 2, 1)
def prepareForScore(self, targets, prediction):
return targets, predictionKey methods to override
| Method | Purpose |
|---|---|
define() |
Build model architecture, assign to self.model |
prepareX(x) |
Reshape/cast input for model forward pass |
prepareY(y) |
Reshape/cast ground truth for loss function |
getLossFunction() |
Return loss function instance |
mapOutputForLoss(output) |
Reshape model output to match loss expectations |
prepareForScore(targets, pred) |
Reshape for metric computation |
ModelManager
ModelManager is a static class that handles model lifecycle. It is used by the Training, Eval and Predict phase to load the model before training and save weights after each epoch.
from pyPhasesML import ModelManager
model = ModelManager.getModel() # load model defined by the config keysModelManager.validate(config) checks that required keys (modelName, modelPath, etc.) are present and raises an error with a clear message if they are missing.
The Training phase calls model.loadWeights(path) before the training loop begins.
Advanded use cases
The model has direct access to the training process, which allows the user defined model to intervene in the training loop. For example, you can implement custom validation logic by overriding the validate() method:
| Method | Purpose |
|---|---|
validate(validationData: DataSet) |
where validation data is scored, should call self.trigger("validationEnd", self, scorer.results, scorer) |
train(dataset: TrainingSetLoader) |
complete training rund, where dataset contains training and validation data |
WIP: more details and examples to come.
Next step
→ Train — configure and run the training loop