Custom parameter types#
The recommended way to implement custom parameter types is by subclassing pyhopper.Parameter() and overwriting its sample and mutate methods.
An example of both options for torch.Tensor type parameters is
import pyhopper
import torch
def dummy_of(param):
print(param)
return 0
class TorchParameter(pyhopper.Parameter):
def __init__(self, size):
super().__init__()
self.size = size
def sample(self):
return torch.normal(0, 1, size=self.size)
def mutate(self, value, temperature: float):
return value + temperature * torch.normal(0, 1, size=self.size)
search = pyhopper.Search(
{
"torch_param": TorchParameter(size=(2, 2)),
}
)
search.run(dummy_of, steps=5, quiet=True)
> {'torch_param': tensor([[ 0.7021, 0.5528], [ 0.3095, -0.1710]])}
> {'torch_param': tensor([[1.1351, 0.2635], [0.8819, 0.8879]])}
> {'torch_param': tensor([[ 0.5685, 1.1966], [ 0.2809, -0.0059]])}
> {'torch_param': tensor([[ 0.7270, 0.9103], [ 0.1998, -0.3033]])}
> {'torch_param': tensor([[0.7232, 0.1011], [0.0034, 0.0875]])}
Alternatively, we can use the pyhopper.custom() parameter template and pass the seeding_fn and mutation_fn functional arguments:
def seeding_fn():
return torch.normal(0, 1, size=(2, 2))
def mutation_fn(current_best):
return current_best + torch.normal(0, 1, size=(2, 2))
search = pyhopper.Search(
{
"other_option": pyhopper.custom(seeding_fn, mutation_fn),
}
)
search.run(dummy_of, steps=5, quiet=True)
> {'other_option': tensor([[ 1.2583, -0.3296], [ 0.5179, 1.3335]])}
> {'other_option': tensor([[ 2.1317, -1.3902], [ 1.8776, 2.1398]])}
> {'other_option': tensor([[-1.0080, 0.9658], [ 0.6401, 1.0016]])}
> {'other_option': tensor([[-0.1377, 0.5059], [-1.1958, 1.3582]])}
> {'other_option': tensor([[1.3503, 0.7410], [1.9922, 1.4300]])}
Tip
To use PyHopper’s built-in parameter type features for torch.Tensor types, we could also just use the built-in NumPy parameters and convert them to torch.Tensor objects.