Skip to content

Commit

Permalink
Style and signatures of deep models.
Browse files Browse the repository at this point in the history
  • Loading branch information
dickensc committed Apr 27, 2024
1 parent c0c0eeb commit e81b88e
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 89 deletions.
115 changes: 67 additions & 48 deletions psl-python/pslpython/deeppsl/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,46 +42,59 @@ def __init__(self):
Higher-level methods that are passed nicely-formatted data for implementing classes to extend.
"""

def internal_init(self, application, options = {}):
def internal_init(self, application, options):
"""
Initialize the model.
:param application: The application that is using the model from ["inference", "learning"].
:param options: Additional options for the model provided by the user in the configuration file.
:return:
"""
raise NotImplementedError("internal_init")

def internal_fit(self, data, gradients, options = {}):
def internal_fit(self, data, gradients, options):
"""
Use the data and gradients to update the model.
:param data: The data used to compute the gradients.
:param gradients: The gradients computed from the data.
:param options: Additional options for the model provided by the user in the configuration file.
:return:
"""
raise NotImplementedError("internal_fit")

def internal_next_batch(self, options = {}):
# Default to doing nothing.
def internal_next_batch(self, options):
"""
Prepare the next batch of data for training.
Default to doing nothing.
:param options:
:return:
"""
return

def internal_train_mode(self, options = {}):
def internal_train_mode(self, options):
"""
Set the model to training mode. Training mode is identified by the _train flag being true.
:param options:
:param options: Additional options for the model provided by the user in the configuration file.
"""
self._train = True
return

def internal_eval_mode(self, options = {}):
def internal_eval_mode(self, options):
"""
Set the model to evaluation mode. Evaluation mode is identified by the _train flag being fals.
:param options:
Set the model to evaluation mode. Evaluation mode is identified by the _train flag being false.
:param options: Additional options for the model provided by the user in the configuration file.
"""
self._train = False
return

def internal_epoch_start(self, options = {}):
def internal_epoch_start(self, options):
# Default to doing nothing.
return

def internal_epoch_end(self, options = {}):
def internal_epoch_end(self, options):
# Default to doing nothing.
return

def internal_is_epoch_complete(self, options = {}):
def internal_is_epoch_complete(self, options):
"""
Default to assuming that the epoch is complete. This is equivalent to assuming a single batch per epoch
Override this method if your model needs to do something special to determine if the epoch is complete.
Expand All @@ -91,43 +104,49 @@ def internal_is_epoch_complete(self, options = {}):
"""
return True

def internal_predict(self, data, options = {}):
def internal_predict(self, data, options):
"""
Use the data to make predictions.
:param data: The data to make predictions with.
:param options: Additional options for the model provided by the user in the configuration file.
:return:
"""
raise NotImplementedError("internal_predict")

def internal_eval(self, data, options = {}):
def internal_eval(self, data, options):
"""
Default to assuming that the model does have an evaluator and return 0.0.
Override this method if your model has an evaluator.
If you do override this method, you must return a dictionary with a key, "loss", that maps to a float where lower is better.
:param data:
:param options:
:param data: The data to evaluate the model with.
:param options: Additional options for the model provided by the user in the configuration file.
:return: A float indicating the loss. Higher is worse.
"""
return 0.0

def internal_save(self, options = {}):
def internal_save(self, options):
raise NotImplementedError("internal_save")

"""
Low-level methods that take care of moving around data.
"""

def init_weight(self, shared_memory_path, application, options = {}):
def init_weight(self, shared_memory_path, application, options):
raise NotImplementedError("init_weight")

def fit_weight(self, options = {}):
def fit_weight(self, options):
raise NotImplementedError("fit_weight")

def predict_weight(self, options = {}):
def predict_weight(self, options):
raise NotImplementedError("predict_weight")

def predict_weight_learn(self, options = {}):
def predict_weight_learn(self, options):
raise NotImplementedError("predict_weight")

def eval_weight(self, options = {}):
def eval_weight(self, options):
raise NotImplementedError("eval_weight")

def init_predicate(self, shared_memory_path, application, options = {}):
def init_predicate(self, shared_memory_path, application, options):
"""
Initialize the model.
:param shared_memory_path: The path to the shared memory file.
Expand All @@ -152,9 +171,9 @@ def init_predicate(self, shared_memory_path, application, options = {}):

self._data = numpy.array(self._data)

return self.internal_init(application, options = options)
return self.internal_init(application, options)

def fit_predicate(self, options = {}):
def fit_predicate(self, options):
self._shared_buffer.seek(0)

count = self._read_int()
Expand All @@ -163,59 +182,59 @@ def fit_predicate(self, options = {}):

data = numpy.array([self._data[index] for index in entity_indexes])

return self.internal_fit(data, gradients, options = options)
return self.internal_fit(data, gradients, options)

def train_mode(self, options = {}):
return self.internal_train_mode(options = options)
def train_mode(self, options):
return self.internal_train_mode(options)

def eval_mode(self, options = {}):
return self.internal_eval_mode(options = options)
def eval_mode(self, options):
return self.internal_eval_mode(options)

def next_batch(self, options = {}):
return self.internal_next_batch(options = options)
def next_batch(self, options):
return self.internal_next_batch(options)

def epoch_start(self, options = {}):
return self.internal_epoch_start(options = options)
def epoch_start(self, options):
return self.internal_epoch_start(options)

def epoch_end(self, options = {}):
return self.internal_epoch_end(options = options)
def epoch_end(self, options):
return self.internal_epoch_end(options)

def is_epoch_complete(self, options = {}):
return self.internal_is_epoch_complete(options = options)
def is_epoch_complete(self, options):
return self.internal_is_epoch_complete(options)

def predict_predicate(self, options = {}):
self._predict_predicate(options = options)
def predict_predicate(self, options):
self._predict_predicate(options)

def _predict_predicate(self, options = {}):
def _predict_predicate(self, options):
self._shared_buffer.seek(0)

count = self._read_int()
entity_indexes = self._read_values('>i4', count)

data = numpy.array([self._data[index] for index in entity_indexes])

predictions, response = self.internal_predict(data, options=options)
predictions, response = self.internal_predict(data, options)

self._shared_buffer.seek(0)

self._write_int(int(options['class-size']) * len(predictions))
predictions = numpy.array(predictions, dtype = '>f4', copy = False)
self._shared_buffer.write(predictions.tobytes(order = 'C'))
predictions = numpy.array(predictions, dtype='>f4', copy=False)
self._shared_buffer.write(predictions.tobytes(order='C'))

return response

def eval_predicate(self, options = {}):
def eval_predicate(self, options):
self._shared_buffer.seek(0)

count = self._read_int()
entity_indexes = self._read_values('>i4', count)

data = numpy.array([self._data[index] for index in entity_indexes])

return self.internal_eval(data, options=options)
return self.internal_eval(data, options)

def save(self, options = {}):
return self.internal_save(options=options)
def save(self, options):
return self.internal_save(options)

"""
Helper methods.
Expand Down
30 changes: 15 additions & 15 deletions psl-python/pslpython/deeppsl/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,9 @@ def _init(self, request):

self._model = self._load_model(os.path.join(options['relative-dir'], options['model-path']))
if deep_model == 'DeepModelPredicate':
return self._model.init_predicate(shared_memory_path, application, options=options)
return self._model.init_predicate(shared_memory_path, application, options)
elif deep_model == 'DeepModelWeight':
return self._model.init_weight(shared_memory_path, application, options=options)
return self._model.init_weight(shared_memory_path, application, options)
else:
raise ValueError("Unknown deep model type in init: '%s'." % (deep_model,))

Expand All @@ -118,38 +118,38 @@ def _fit(self, request):
options = request.get('options', {})

if deep_model == 'DeepModelPredicate':
return self._model.fit_predicate(options=options)
return self._model.fit_predicate(options)
elif deep_model == 'DeepModelWeight':
return self._model.fit_weight(options=options)
return self._model.fit_weight(options)
else:
raise ValueError("Unknown deep model type in fit: '%s'." % (deep_model,))

def _train_mode(self, request):
return self._model.train_mode(options=request.get('options', {}))
return self._model.train_mode(request.get('options', {}))

def _eval_mode(self, request):
return self._model.eval_mode(options=request.get('options', {}))
return self._model.eval_mode(request.get('options', {}))

def _next_batch(self, request):
return self._model.next_batch(options=request.get('options', {}))
return self._model.next_batch(request.get('options', {}))

def _epoch_start(self, request):
return self._model.epoch_start(options=request.get('options', {}))
return self._model.epoch_start(request.get('options', {}))

def _epoch_end(self, request):
return self._model.epoch_end(options=request.get('options', {}))
return self._model.epoch_end(request.get('options', {}))

def _is_epoch_complete(self, request):
return self._model.is_epoch_complete(options=request.get('options', {}))
return self._model.is_epoch_complete(request.get('options', {}))

def _predict(self, request):
deep_model = request['deep_model']
options = request.get('options', {})

if deep_model == 'DeepModelPredicate':
return self._model.predict_predicate(options=options)
return self._model.predict_predicate(options)
elif deep_model == 'DeepModelWeight':
return self._model.predict_weight(options=options)
return self._model.predict_weight(options)
else:
raise ValueError("Unknown deep model type in predict: '%s'." % (deep_model,))

Expand All @@ -158,15 +158,15 @@ def _eval(self, request):
options = request.get('options', {})

if deep_model == 'DeepModelPredicate':
return self._model.eval_predicate(options=options)
return self._model.eval_predicate(options)
elif deep_model == 'DeepModelWeight':
return self._model.eval_weight(options=options)
return self._model.eval_weight(options)
else:
raise ValueError("Unknown deep model type in eval: '%s'." % (deep_model,))

def _save(self, request):
options = request.get('options', {})
return self._model.save(options=options)
return self._model.save(options)

def _close(self):
if self._model is not None:
Expand Down
16 changes: 8 additions & 8 deletions psl-python/tests/resources/models/deeppsl/sign/pytorch_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def __init__(self):
self._loss = None
self._optimizer = None

def internal_init(self, application, options = {}):
def internal_init(self, application, options):
class SignPytorchNetwork(torch.nn.Module):
def __init__(self, input_size, output_size):
_import()
Expand All @@ -54,7 +54,7 @@ def forward(self, x):

return {}

def internal_fit(self, data, gradients, options = {}, verbose=0):
def internal_fit(self, data, gradients, options, verbose=0):
features = torch.FloatTensor(data[0])
labels = torch.FloatTensor(data[1])

Expand All @@ -68,24 +68,24 @@ def internal_fit(self, data, gradients, options = {}, verbose=0):
self._optimizer.step()
return {}

def internal_predict(self, data, options = {}, verbose=0):
def internal_predict(self, data, options, verbose=0):
features = torch.FloatTensor(data[0])
predictions = self._model(features)
return predictions, {}

def internal_eval(self, data, options = {}):
predictions, _ = self.internal_predict(data, options=options)
def internal_eval(self, data, options):
predictions, _ = self.internal_predict(data, options)
results = {'loss': self._loss(self._model(torch.FloatTensor(data[0])), torch.FloatTensor(data[1])).item(),
'metrics': calculate_metrics(predictions.detach().numpy(), data[1], self._metrics)}

return results

def internal_save(self, options = {}):
def internal_save(self, options):
torch.save(self._model.state_dict(), options['save_path'])
return {}

def load(self, options = {}):
self.internal_init(None, options=options)
def load(self, options):
self.internal_init(None, options)
self._model.load_state_dict(torch.load(options['load_path']))
return {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,25 @@ def __init__(self):
self._model = None
self._metrics = ['categorical_accuracy']

def internal_init(self, application, options = {}):
def internal_init(self, application, options):
self._model = tree.DecisionTreeClassifier()
return {}

def internal_fit(self, data, gradients, options = {}):
def internal_fit(self, data, gradients, options):
self._model.fit(numpy.array(data[0]), numpy.array(data[1]))
return {}

def internal_predict(self, data, options = {}):
def internal_predict(self, data, options):
predictions = self._model.predict(data[0])
return predictions, {}

def internal_eval(self, data, options = {}):
predictions, _ = self.internal_predict(data);
def internal_eval(self, data, options):
predictions, _ = self.internal_predict(data, options)
results = {'metrics': calculate_metrics(predictions, data[1], self._metrics)}

return results

def internal_save(self, options = {}):
def internal_save(self, options):
return {}


Expand Down
Loading

0 comments on commit e81b88e

Please sign in to comment.