brainspy.utils package#
Module contents#
A set of classes to provide support in useful tasks that are typically required when using the library. Check https://github.com/BraiNEdarwin/brains-py/wiki/C.-Package-Description
Subpackages#
Submodules#
brainspy.utils.io module#
Library that handles loading and saving of data to a file. It is also used to create a new directory with a timestamp.
- class brainspy.utils.io.IncludeLoader(*args, **kwargs)[source]#
Bases:
LoaderClass to handle !include directives in config files. This allows you to load the contents of a file from within a file and therefore multiple files can be loaded into a dict by simply using !include “filename/filepath”
When constructed with a file object, the root path for “include” defaults to the directory containing the file, otherwise to the current working directory. In either case, the root path can be overridden by the root keyword argument. When an included file F contain its own !include directive, the path is relative to F’s location.
Example
Given two yaml files file1.yaml and file2.yaml file1.yaml -
>>> processor : simulation >>> algorithm : !include file2.yaml
file2.yaml -
>>> optimizer : genetic
When loading file1.yaml, you will get a dictionary in which file2.yaml is already incorporated:
>>> file = open(self.path + "file1.yaml", "r") --loading the file >>> loader = IncludeLoader(file) >>> data = loader.get_data()
The result is a data : dict with the following keys and values of data: >>> processor : simulation >>> algorithm : >>> optimizer : genetic
- brainspy.utils.io.create_directory(path: str, overwrite=False)[source]#
Checks if there exists a directory with - filepath+datetime_name , and if not it will create it and return this path.
- Parameters:
path (str) – File object or path to file
overwrite (boolean) – When True, if the directory exists, it will overwrite it. When False, if the directory exists it will not do anything. By default is False.
Example
path = “tests/unit/utils/testfiles” newpath = create_directory(path + “/TestDirectory”)
- brainspy.utils.io.create_directory_timestamp(path: str, name: str, overwrite=False)[source]#
To create a directory with the given name and current timestamp if it does not already exist.
- Parameters:
path (str) – File object or path to file
name (str) –
- Returns:
str
- Return type:
Path to file created - filepath+datetime_name
Example
path = “tests/unit/utils/testfiles” name = “TestDirectory” new_directory = create_directory_timestamp(self.path, name)
- brainspy.utils.io.load_configs(file_name: str)[source]#
Loads a yaml file from the given file path.
- Parameters:
file_name (str) – File object or path to yaml file.
- Returns:
dict
- Return type:
Python dictionary with formatted yaml data.
Example
file = “boolean.yaml” data = load_configs(file)
- brainspy.utils.io.save_configs(configs: dict, file_name: str)[source]#
Formats data from a dictionary and saves it to the given yaml file.
- Parameters:
configs (dict) – Data to be stored in the yaml file.
file_name (str) – File object or path to yaml file.
Example
configs = {“data” : “example”} file = “boolean.yaml” save_configs(configs,file)
brainspy.utils.manager module#
Class to retrieve data specified in a dictionary used to train a model. The class methods require a configuration dictionary with data keys specific to do a task. It can be used to get an optimizer,fitness function,driver or an algorithm for training a model.
- brainspy.utils.manager.get_adam(model: object, configs: dict = {})[source]#
To get an Adam optimizer object which include added information to train a specific model. It is for first-order gradient-based optimization of stochastic objective functions, based on adaptive estimates of lower-order moments.
- Parameters:
model (torch.nn.Module) – A Module object which can be a DNPU,Processor or a SurrogateModel object.
configs (dict) – Configurations of the adam optimizer. The configurations do not require to have all of these keys. The keys of the dictionary are as follows: 1. learning_rate: float 2. betas: Tuple[float, float] 3. epsilon: float 4. weight_decay: float 5. amsgrad: boolean More information on what these keys do can be found at: https://pytorch.org/docs/stable/generated/torch.optim.Adam.html#torch.optim.Adam
- Returns:
class object
- Return type:
Returns and optimizer Adam optimizer object.
Example
configs = {“learning_rate”: 0.0001} model = torch.nn.Linear(1,1) optimizer = get_adam(model,configs)
- brainspy.utils.manager.get_algorithm(name: str)[source]#
To get a default train function for either GA - genetic algorithm or GD - Gradient Descent, based on its name.
A genetic algorithm (GA), in computer science and operations research, is a meta-heuristic inspired by the process of natural selection that belongs to the larger class of evolutionary algorithms (EA). Genetic algorithms are commonly used to generate high-quality solutions to optimization and search problems by relying on bio-inspired operators such as mutation, crossover and selection. This algorithm is suitable for experiments with reservoir computing.
A gradient descent algorithm (GD) is a first-order iterative optimization algorithm for finding the minimum of a function. To find a local minimum of a function using gradient descent, one takes steps proportional to the negative of the gradient (or approximate gradient) of the function at the current point.
- Parameters:
name (str) – Name of the algorithm. The string value can either be ‘gradient’ or ‘genetic’.
- Returns:
A method containting a default training function for GA or GD as defined in from
brainspy.algorithms.ga/gd.
Example
For a fetching the genetic algorithm: >>> algorithm = get_algorithm(‘genetic’)
For fetching the gradient descent algorithm: >>> algorithm = get_algorithm(‘gradient’)
- brainspy.utils.manager.get_criterion(name: str)[source]#
Returns a loss/fitness function from brainspy.algorithms.modules.signal module given a string name.
- Parameters:
name (str) – Name of the criterion that will be instantiated from brainspy.algorithms.modules.signal
- Return type:
A method from brainspy.algorithms.modules.signal containing either a loss or a fitness function.
Example
criterion = get_criterion(“corr_fit”)
- brainspy.utils.manager.get_driver(configs: dict)[source]#
To get an instance of a driver object from brainspy.processors.hardware.drivers.nidaq/cdaq based on a configurations dictionary. The driver here are defined under the processor type tag in the configs dictionary and can be a
1. SurrogateModel (Software processor) - It is a deep neural network with information about the control voltage ranges, the amplification of the device and relevant noise simulations that it may have.
2. Hardware Processor - It establishes a connection (for a single, or multiple hardware DNPUs) with one of the following National Instruments measurement devices. * CDAQ-to-NiDAQ * CDAQ-to-CDAQ
- Parameters:
configs (dict) – Configurations of the model.
- Raises:
NotImplementedError – If configurations is not recognised.:
- Returns:
brainspy.processors.hardware.drivers.ni.NationalInstrumentsSetup (Returns and driver object)
which can be CDAQtoCDAQ or CDAQtoNiDAQ.
Example
Example to load a CDAQtoNiDAQ driver (differnt configurations can be provided for differt drivers)
>>> configs = {} >>> configs["processor_type"] = "cdaq_to_nidaq" >>> configs["input_indices"] = [2, 3] >>> configs["electrode_effects"] = {} >>> configs["electrode_effects"]["amplification"] = 3 >>> configs["electrode_effects"]["clipping_value"] = [-300, 300] >>> configs["electrode_effects"]["noise"] = {} >>> configs["electrode_effects"]["noise"]["noise_type"] = "gaussian" >>> configs["electrode_effects"]["noise"]["variance"] = 0.6533523201942444 >>> configs["driver"] = {}
>>> configs["driver"]["instruments_setup"] = {} >>> configs["driver"]["instruments_setup"]["multiple_devices"] = False >>> configs["driver"]["instruments_setup"]["trigger_source"] = "cDAQ1/segment1" >>> configs["driver"]["instruments_setup"]["activation_instrument"] = "cDAQ1Mod3" >>> configs["driver"]["instruments_setup"]["activation_sampling_frequency"] = 1000 >>> configs["driver"]["instruments_setup"]["activation_channels"] = [ >>> 0, >>> 2, >>> 5, >>> 3, >>> 4, >>> 6, >>> 1, >>> ] >>> configs["driver"]["instruments_setup"]["activation_voltages"] = [ >>> [-1.2, 0.6], >>> [-1.2, 0.6], >>> [-1.2, 0.6], >>> [-1.2, 0.6], >>> [-1.2, 0.6], >>> [-0.7, 0.3], >>> [-0.7, 0.3], >>> ] >>> configs["driver"]["instruments_setup"]["readout_instrument"] = "cDAQ1Mod4" >>> configs["driver"]["instruments_setup"]["readout_sampling_frequency"] = 1000 >>> configs["driver"]["instruments_setup"]["readout_channels"] = [ >>> 4 >>> ] >>> configs["waveform"] = {} >>> configs["waveform"]["plateau_length"] = 10 >>> configs["waveform"]["slope_length"] = 30 >>> driver = get_driver(configs)
- brainspy.utils.manager.get_optimizer(model: object, configs: dict)[source]#
Gets either a genetic algorithm or a gradient descent pytorch optimizer object from a dictionary.
- Parameters:
object) (Model (nn.Module) –
descent (a SurrogateModel. On the gradient) –
learnable (it is required to gather the) –
algorithm (parameters from the model. On the genetic) –
the (it is required to gather) –
ranges. (control) –
configs (1.) –
or (This configuration is different depending on whether a genetic) –
requested. (a gradient descent optimiser is) –
keys (1.2 For genetic algorithm) –
keys –
(Optional) (1.2.1 Gene range) –
present (electrodes. If this key is not) –
automatically (the gene range will be calculated) –
model. (from the control electrode range function of the) –
Partition (1.2.2) –
Epochs (1.2.3) –
- Returns:
Returns an object which can be a brainspy.algorithms.optim.GeneticOptimizer or
an torch.optim.Adam optimizer
Example
A simple example can be: >>> configs = {“optimizer” : “genetic”, >>> “partition”: [4,22], >>> “epochs”: 100}
>>> model = CustomDNPUModel()
>>> optimizer = get_optimizer(model,configs)
Another example can be:
>>> configs = {"optimizer" : "adam", "learning_rate": 1e-3}
>>> model = torch.nn.Linear(1,1)
>>> optimizer = get_optimizer(model,configs)
brainspy.utils.pytorch module#
Class to consistently manage torch variables and their data types. It can format data provided as a torch tensor,numpy array or an nn.Module object. It also han- dles the intialization of seed for generation of random values.
- class brainspy.utils.pytorch.TorchUtils[source]#
Bases:
objectConsistently manage data movement and formatting of pytorch tensors and torch.nn.Module instances. This includes data movement to/from CUDA and CPU, as well as transformations to/ from lists and numpy arrays. It also enables to manage the seeds for reproducibility purpo- ses. More information can be found at: https://pytorch.org/docs/stable/torch.html https://pytorch.org/docs/stable/notes/randomness.html
- force_cpu = False#
- static format(data, device=None, data_type=None)[source]#
If a list or a numpy array is provided, it enables to create a torch variable with a consistent accelerator type and data type. If an exisiting torch tensor is provided, the function enables setting the data type and device consistently for all torch tensors. For devices with more than one GPU, if an instance of an nn.Module is provided, for example CustomModel,DNPU or Processor, this function helps to distribute the model.
- Parameters:
data (Data to be formatted. It can be one of these data types:) – list : list of data indices np.ndarray : list of data indices torch.Tensor : inital torch tensor which has to be formatted nn.Module : model of an nn.Module object
device (torch.device, optional) – Device type of torch tensor which can be “cpu or “cuda” depending on computer version. When set to none, it will take the default value from the global variable force_cpu of this class. By default device is set to None.
data_type (torch.dtype, optional) – desired data type of torch tensor, by default None When set to None, it will take the default data type from pytorch. This datatype can be changed using the torch.set_default_dtype. More info on this method at: https://pytorch.org/docs/stable/generated/torch.set_default_dtype.html
- Returns:
1. torch.tensor – Torch tensor either generated from python list or numpy array, or exisiting torch tensors formatted to given device and data type.
2. nn.Module – If an nn.Module is given as an argument, a model of the nn.Module object distributed by DataParallel amongst the multiple GPUs is generated.
Examples
data = [[1, 2]] tensor = TorchUtils.format(data, device=torch.device(‘cpu’))
tensor = torch.randn(2, 2) tensor = TorchUtils.format(tensor, data_type=torch.float64)
data = [[1, 2], [3, 4]] numpy_data = np.array(data) tensor = TorchUtils.format(numpy_data)
model = CustomModel() # Where CustomModel is an instance of torch.nn.Module newmodel = format_model(model)
- static get_device()[source]#
Consistently returns the device type for the torch. The device type can be “cpu” or “cuda”, depending on if the computer has a GPU with a cuda installation, and on the variable force_cpu. This method does not support the management of multiple GPUs.
- Returns:
Device type of torch tensor which can be “cpu” or “cuda” depending on computer version.
- Return type:
torch.device
Example
TorchUtils.get_device()
- static init_seed(seed=None, deterministic=False)[source]#
It enables to set a fixed seed, or retrieve the current seed used for generating random numbers. If the random seed is not reset, different numbers appear with every invocation. It can be used to reproduce results. More information at: https://pytorch.org/docs/stable/notes/randomness.html
- Parameters:
seed (int, optional) – Value of seed, by default None.
deterministic (bool, optional) – If the random value should be deterministic, by default False.
- Returns:
Value of the seed that is being used.
- Return type:
int
Example
TorchUtils.init_seed(0) random1 = np.random.rand(4)
- static set_force_cpu(force: bool)[source]#
Facilitates running all tensors on the CPU even when having a GPU with cuda correctly installed. Ideal for GPUs that do not have enough memory to run certain experiments or for computers with or with older GPUs. Also, for cases where torch detects that there is cuda, but the version is too old to be compatible.
- Parameters:
force (boolean) – True or false to set the force_cpu option to detect cuda.
Example
TorchUtils.set_force_cpu(True)
- static to_numpy(data: Tensor)[source]#
Transforms torch tensor into a numpy array, detatching it first, and moving the data to the cpu (if needed). The aim is to simplify the lines of code required for this purpose with the original pytorch library.
- Parameters:
data (torch.tensor) – Torch tensor that needs to be formatted to a numpy array.
- Returns:
Numpy array from given torch tensor.
- Return type:
np.array
Example
tensor = torch.tensor([[1., -1.], [1., -1.]]) numpy_data = TorchUtils.to_numpy(tensor)
brainspy.utils.signal module#
Set of fitness functions for genetic algorithm and loss functions for gradient descent.
- brainspy.utils.signal.accuracy_fit(output: Tensor, target: Tensor, default_value=False) Tensor[source]#
Fitness function for genetic algorithm using accuracy of a perceptron. Teaches single perceptron to transform output to target and evaluates the accuracy; is a percentage. Will return default value (0) if indicated.
Needs at least 10 datapoints in each signal.
Example
>>> accuracy_fit(torch.rand((100, 3)), torch.rand(100, 3)) torch.Tensor([48., 21.2, 3.5]) >>> accuracy_fit(torch.rand((100, 3)), torch.rand(100, 3), True) torch.Tensor([0.0, 0.0, 0.0])
- Parameters:
output (torch.Tensor) – The output data, shape [n, m] with m signals of n datapoints.
target (torch.Tensor) – The target data, shape [n, m] with m signals of n datapoints.
default_value (bool, optional) – Return the default value or not, by default False.
- Returns:
Default value or calculated fitness for each pair of signals.
- Return type:
torch.Tensor
- Raises:
AssertionError – If dimensions of output and target are not the same.
- brainspy.utils.signal.corr_fit(output: Tensor, target: Tensor, default_value=False) Tensor[source]#
Fitness function for genetic algorithm using Pearson correlation. See pearsons_correlation for more info. Will return default value (-1) if indicated.
Example
>>> corr_fit(torch.rand((100, 3)), torch.rand(100, 3)) torch.Tensor([0.5, 0.4, -0.34]) >>> corr_fit(torch.rand((100, 3)), torch.rand(100, 3), True) torch.Tensor([-1.0, -1.0, -1.0])
- Parameters:
output (torch.Tensor) – The output data, shape [n, m] with m signals of n datapoints.
target (torch.Tensor) – The target data, shape [n, m] with m signals of n datapoints.
default_value (bool, optional) – Return the default value or not, by default False.
- Returns:
Default value or calculated fitness for each pair of signals.
- Return type:
torch.Tensor
- Raises:
AssertionError – If dimensions of output and target are not the same.
- brainspy.utils.signal.corrsig(output: Tensor, target: Tensor, sigmoid_center: float = 0, sigmoid_scale: float = 1, corr_shift: float = 1.1) Tensor[source]#
Loss function for gradient descent using a sigmoid function.
For values of parameters see this paper: https://www.nature.com/articles/s41565-020-00779-y
Example
>>> corrsig(torch.rand((100, 1)), torch.round(torch.rand((100, 1)))) torch.Tensor(2.5)
- Parameters:
output (torch.Tensor) – The output data, shape [n, m] with m signals of n datapoints.
target (torch.Tensor) – The target data, shape [n, m] with m signals of n datapoints; should be binary.
sigmoid_center (float) – Center of the sigmoid.
sigmoid_scale (float) – Scale of the sigmoid, between 0 and 1.
corr_shift (float) – Shifting the correlation value.
- Returns:
Value of loss function for each pair of signals.
- Return type:
torch.Tensor
- Raises:
AssertionError – If dimensions of x and y are not the same.
- brainspy.utils.signal.corrsig_fit(output: Tensor, target: Tensor, default_value=False, sigmoid_center=0, sigmoid_scale=1) Tensor[source]#
Fitness function for genetic algorithm using correlation and a sigmoid function. Will return default value (-1) if indicated.
For values of parameters see this paper: https://www.nature.com/articles/s41565-020-00779-y
Note: target data must be binary for this to work.
Example
>>> corrsig_fit(torch.rand((100, 3)), torch.round(torch.rand(100, 3))) torch.Tensor([0.5, 0.4, -0.34]) >>> corrsig_fit(torch.rand((100, 3)), torch.round(torch.rand(100, 3)), True) torch.Tensor([-1.0, -1.0, -1.0])
- Parameters:
output (torch.Tensor) – The output data, shape [n, m] with m signals of n datapoints.
target (torch.Tensor) – The target data, shape [n, m] with m signals of n datapoints; should be binary.
default_value (bool, optional) – Return the default value or not, by default False.
sigmoid_center (float) – Shift of the sigmoid, by default 0.
sigmoid_scale (float) – Scale of the sigmoid, by default 1.
- Returns:
Default value or calculated fitness for each pair of signals. Will be NaN if target data is not binary.
- Return type:
torch.Tensor
- Raises:
AssertionError – If dimensions of output and target are not the same.
- brainspy.utils.signal.fisher(output: Tensor, target: Tensor) Tensor[source]#
Calculate the negative of the Fisher linear discriminant between two datasets. Used as a loss function for gradient descent.
More information here: https://sthalles.github.io/fisher-linear-discriminant/
Example
>>> fisher(torch.rand((100, 3)), torch.rand((100, 3)), False) torch.Tensor([2.5, 1.2, 0.5])
- Parameters:
output (torch.Tensor) – Dataset, shape [n, m] with m signals of n datapoints.
target (torch.Tensor) – Dataset, shape [n, m] with m signals of n datapoints; should be binary.
- Returns:
Value of Fisher linear discriminant for each pair of signals.
- Return type:
torch.Tensor
- Raises:
AssertionError – If dimensions of x and y are not the same.
UserWarning – If result is nan (which happens if a dataset has variance 0, is uniform).
- brainspy.utils.signal.fisher_fit(output: Tensor, target: Tensor, default_value=False) Tensor[source]#
Fitness function for genetic algorithm using the negative of the Fisher linear discriminant. For more information see fisher method.
Can return default value (0).
Example
>>> fisher_fit(torch.rand((100, 3)), torch.rand((100, 3)), False) torch.Tensor([2.5, 1.2, 0.5]) >>> fisher_fit(torch.rand((100, 3)), torch.rand((100, 3)), True) torch.Tensor([0.0, 0.0, 0.0])
- Parameters:
output (torch.Tensor) – The output data, shape [n, m] with m signals of n datapoints.
target (torch.Tensor) – The target data, shape [n, m] with m signals of n datapoints; should be binary.
default_value (bool, optional) – Return the default value or not, by default False.
- Returns:
Default value or calculated fitness for each pair of signals.
- Return type:
torch.Tensor
- Raises:
AssertionError – If dimensions of x and y are not the same.
- brainspy.utils.signal.get_clamped_intervals(output: Tensor, mode: str, boundaries=[0.0, 1.0]) Tensor[source]#
Sort and clamp the data, and find the distances between the datapoints.
There are three modes: “single_nn” - for each point the smaller distance to a neighbor “double_nn” - simply the distances between the points “intervals” - for each point the summed distance to the point in front and behind it
Example
>>> output = torch.tensor([3.0, 1.0, 8.0, 9.0, 5.0]).unsqueeze(dim=1) >>> clamp = [1, 9] >>> get_clamped_intervals(output, "single_nn", clamp) torch.tensor([0.0, 2.0, 2.0, 1.0, 0.0]) >>> get_clamped_intervals(output, "double_nn", clamp) torch.tensor([0.0, 2.0, 2.0, 3.0, 1.0, 0.0]) >>> get_clamped_intervals(output, "intervals", clamp) torch.tensor([2.0, 4.0, 5.0, 4.0, 1.0])
Here we have a dataset which ordered is 1, 3, 5, 8, 9. The distances between the points are 0, 2, 2, 3, 1, 0 (double). The smaller distance for each is 0, 2, 2, 1, 0 (single). The sum from both sides is 2, 4, 5, 4, 1 (intervals).
- Parameters:
output (torch.Tensor) – Dataset, shape [n, m] with m signals of n datapoints.
mode (str) – Mode for nearest neighbor. Can be “single_nn”, “double_nn” or “intervals”
boundaries (list[float], optional) – Boundary values for clamping [min, max].
- Returns:
Distances between the datapoints.
- Return type:
torch.Tensor
- Raises:
UserWarning – If mode not recognized.
- brainspy.utils.signal.pearsons_correlation(x: Tensor, y: Tensor) Tensor[source]#
Measure the Pearson correlation between two sets of data (how much the two sets are linearly related). Value is between -1 and 1, where 1 is positive correlation, -1 is negative, and 0 is no correlation.
An explanation and the formula for correlation: https://www.socscistatistics.com/tests/pearson/
Example
>>> pearsons_correlation(torch.rand((100, 1)), torch.rand((100, 1))) torch.Tensor(0.5)
- Parameters:
x (torch.Tensor) – Dataset, shape [n, m] with m signals of n datapoints.
y (torch.Tensor) – Dataset, shape [n, m] with m signals of n datapoints.
- Returns:
Correlation between x and y for each pair of signals. Will be nan if a data is uniform.
- Return type:
torch.Tensor
- Raises:
AssertionError – If dimensions of x and y are not the same.
UserWarning – If result is nan (which happens if a dataset has variance 0, is uniform).
- brainspy.utils.signal.sigmoid_nn_distance(output: Tensor, target: Tensor | None = None, sigmoid_center: float = 0.5, sigmoid_scale: float = 2.0) Tensor[source]#
Sigmoid of nearest neighbour distance: a squashed version of a sum of all internal distances between points. Used as a loss function for gradient descent.
For values of parameters see this paper: https://www.nature.com/articles/s41565-020-00779-y
Example
>>> sigmoid_nn_distance(torch.rand((100, 3))) torch.Tensor([20.0, 11.0, 10.0])
- Parameters:
output (torch.Tensor) – The output data, shape [n, m] with m signals of n datapoints.
target (torch.Tensor) – The target data, will not be used.
sigmoid_center (float) – Center of the sigmoid.
sigmoid_scale (float) – Scale of the sigmoid, between 0 and 1.
- Returns:
Sigmoid of the sum of the nearest neighbor distances (output).
- Return type:
torch.Tensor
- Raises:
UserWarning – If target data is provided to warn that it will not be used.
brainspy.utils.transforms module#
File that contains a set of methods to perform linear transformation from a given range to the range of the activation electrodes.
- brainspy.utils.transforms.check_values(x_max, x_min, y_max, y_min)[source]#
To check wheather the arguments provided to the functions - get_offset and get_scale are valid by raising an Assertion Error if x_max < x_min or y_max < y_min
- Parameters:
y_min (torch.Tensor) – Y-coordinate of first point. In a current to voltage linear transformation, the expected minimum value(s) for the voltage.
y_max (torch.Tensor) – Y-coordinate of second point. In a current to voltage linear transformation, the expected maximum value(s) for the voltage.
x_min (torch.Tensor) – X-coordinate of first point. In a current to voltage linear transformation, the expected minimum value(s) for the current.
x_max (Torch.Tensor) – X-coordinate of second point. In a current to voltage linear transformation, the expected minimum value(s) for the current.
- Raises:
AssertionError – raised if x_max < x_min when the type of the arguments are int or float
AssertionError – raised if y_max < y_min when the type of the arguments are int or float
AssertionError – raised if x_max < x_min when the arguments are provided as torch tensors
AssertionError – raised if y_max < y_min when the arguments are provided as torch tensors
- brainspy.utils.transforms.get_linear_transform_constants(y_min: Tensor, y_max: Tensor, x_min: Tensor, x_max: Tensor) Tuple[Tensor, Tensor][source]#
Get the scale and offset of a line defined by two points. The two points are expressed as torch tensors. Used to transform current data to the input voltage ranges of a device: Current range would be (x_min, x_max), voltage range would be (y_min, y_max).
Example
>>> get_linear_transform_constants(x_min=1, y_min=1, x_max=2, y_max=0) (-1, 2)
This gives the line defined by the points (1, 1) and (2, 0), which is y = 2 - x. The function will return the scale and offset, which are -1 and 2 respectively.
>>> get_linear_transform_constants(x_min=torch.tensor([[1, 4]]), y_min=torch.tensor([[16, 14]]), x_max=torrch.tensor([[7, 4]]), y_max=torch.tensor([[12, 14]])) (tensor([[0.3333, 1.0000]]), tensor([[6.6667, -0.0000]]))
- Parameters:
y_min (torch.Tensor) – Y-coordinate of first point. In a current to voltage linear transformation, the expected minimum value(s) for the voltage.
y_max (torch.Tensor) – Y-coordinate of second point. In a current to voltage linear transformation, the expected maximum value(s) for the voltage.
x_min (torch.Tensor) – X-coordinate of first point. In a current to voltage linear transformation, the expected minimum value(s) for the current.
x_max (torch.Tensor) – X-coordinate of second point. In a current to voltage linear transformation, the expected minimum value(s) for the current.
- Returns:
[scale,offset]
scale (torch.Tensor) – Scale of the line.
offset (torch.Tensor) – Offset of the line.
- Raises:
ZeroDivisionError – If x_min equals x_max division by 0 occurs.
- brainspy.utils.transforms.get_offset(y_min: Tensor, y_max: Tensor, x_min: Tensor, x_max: Tensor) Tensor[source]#
Get the offset/y-intercept of a line defined by two points. The points are expressed as torch tensors. Used to transform current data to the input voltage ranges of a device: Current range would be (x_min, x_max), voltage range would be (y_min, y_max).
Example
>>> get_offset(x_min=1, y_min=1, x_max=2, y_max=0) 2
This gives the line defined by the points (1, 1) and (2, 0), which is y = 2 - x. The function will return the offset, which is 2.
>>> get_offset(x_min=torch.tensor([[1, 4]]), y_min=torch.tensor([[16, 14]]), x_max=torrch.tensor([[7, 4]]), y_max=torch.tensor([[12, 14]])) tensor([[6.6667, -0.0000]])
- Parameters:
y_min (torch.Tensor) – Y-coordinate of first point. In a current to voltage linear transformation, the expected minimum value(s) for the voltage.
y_max (torch.Tensor) – Y-coordinate of second point. In a current to voltage linear transformation, the expected maximum value(s) for the voltage.
x_min (torch.Tensor) – X-coordinate of first point. In a current to voltage linear transformation, the expected minimum value(s) for the current.
x_max (Torch.Tensor) – X-coordinate of second point. In a current to voltage linear transformation, the expected minimum value(s) for the current.
- Returns:
The offset of the line.
- Return type:
torch.Tensor
- Raises:
ZeroDivisionError – If x_min equals x_max division by 0 occurs.
- brainspy.utils.transforms.get_scale(y_min: Tensor, y_max: Tensor, x_min: Tensor, x_max: Tensor) Tensor[source]#
Get the scale/slope of a line defined by two points. The points are expressed as torch tensors. Used to transform current data to the input voltage ranges of a device: Current range would be (x_min, x_max), voltage range would be (y_min, y_max).
Example
>>> get_scale(x_min=1, y_min=1, x_max=2, y_max=0) -1
This gives the line defined by the points (1, 1) and (2, 0), which is y = 2 - x. The function will return the scale, which is -1.
>>> get_scale(x_min=torch.tensor([[1, 4]]), y_min=torch.tensor([[16, 14]]), x_max=torrch.tensor([[7, 4]]), y_max=torch.tensor([[12, 14]])) tensor([[0.3333, 1.0000]])
- Parameters:
y_min (torch.Tensor) – Y-coordinate of first point. In a current to voltage linear transformation, the expected minimum value(s) for the voltage.
y_max (torch.Tensor) – Y-coordinate of second point. In a current to voltage linear transformation, the expected maximum value(s) for the voltage.
x_min (torch.Tensor) – X-coordinate of first point. In a current to voltage linear transformation, the expected minimum value(s) for the current.
x_max (torch.Tensor) – X-coordinate of second point. In a current to voltage linear transformation, the expected minimum value(s) for the current.
- Returns:
The scale of the line.
- Return type:
torch.Tensor
- Raises:
ZeroDivisionError – If x_min equals x_max division by 0 occurs.
- brainspy.utils.transforms.linear_transform(y_min, y_max, x_min, x_max, x_val)[source]#
Define a line by two points. Evaluate it at a given point. The points are expressed as float values or as torch tensors. Used to transform current data to the input voltage ranges of a device: Current range would be (x_min, x_max), voltage range would be (y_min, y_max).
Example
>>> linear_transform(x_min=1, y_min=1, x_max=2, y_max=0, x_val=1) 1
This gives the line defined by the points (1, 1) and (2, 0), which is y = 2 - x. The function will return the line evaluated at x = 1, which is 1.
- Parameters:
x_val (float,torch.Tensor) – Point at which the line is evaluated.
y_min (float,torch.Tensor) – Y-coordinate of first point.
y_max (float,torch.Tensor) – Y-coordinate of second point.
x_min (float,torch.Tensor) – X-coordinate of first point.
x_max (float,torch.Tensor) – X-coordinate of second point.
- Returns:
The line is defined by w and b and evaluated at x_val.
- Return type:
float or torch.Tensor (depending on the type of the parameters)
- Raises:
ZeroDivisionError – If x_min equals x_max division by 0 occurs.
brainspy.utils.waveform module#
This module is part of the utils of brains-py helps managing the waveforms of the signals sent to and received by the hardware DNPUs.
Data can exist in 3 forms: -points (e.g. (1, 2, 3)) -plateaus (e.g. (1, 1, 1, 2, 2, 2, 3, 3, 3)) -waveform (e.g (0, 0.5, 1, 1, 1, 1, 1, 1.5, 2, 2, 2, 2, 2, 2.5, 3, 3, 3, 3, 3, 1.5, 0)) A waveform transform is defined by its plateau length and slope length, in the case above 3 and 3 respectively. There are methods in this module that define the transformations between these three forms.
The goal of the waveform representation of data is so that it can be applied to DNPUs without sudden changes in input, so that the hardware is not damaged.
- class brainspy.utils.waveform.WaveformManager(configs)[source]#
Bases:
objectThis class helps managing the waveforms of the signals sent to and received by the hardware DNPUs (Dopant Network Processing Units).
The waveform represents a set of points. Each of the points is represented with a slope, a plateau and another slope. The first slope is a line that goes from the previous point to the current point value. The plateau repeats the same point a specified number of times. The second slope is a line that goes from the current point to the next point. The starting and ending points are considered zero.
- Parameters:
plateau_length (int) – The length of the plateaus of this manager.
slope_length (int) – The length of the slopes of this manager.
initial_mask (List[bool]) – A mask that covers one slope and one plateau. False where there is a slope, True where there is a plateau.
final_mask (List[bool]) – A mask that covers one plateau - consists entirely of False.
- generate_mask(data_size: int) Tensor[source]#
Use self.mask and self.final_mask to make a mask for input of given size: if there are 3 data points, return self.mask * 3 + self.final_mask self.mask is [False] * self.slope_length + [True] * self.plateau_length self.final_mask is [False] * self.slope_length
Assume the data size is valid.
Example
>>> configs = {"plateau_length": 2, "slope_length": 1} >>> manager = WaveformManager(configs) >>> manager.generate_mask(7) torch.tensor([False, True, True, False, True, True, False])
This example has two plateaus of length 2 and 3 slopes of length 1.
- Parameters:
data_size (int) – The number of points in the data.
- Returns:
A mask of the required length.
- Return type:
torch.Tensor
- generate_mask_base()[source]#
To generate a mask base for the torch tensor based on the slope length and plateau_length.
Example
configs = {} configs[“plateau_length”] = 80 configs[“slope_length”] = 20 waveform_mgr = WaveformManager(configs) waveform_mgr.generate_mask_base()
- plateaus_to_points(data: Tensor) Tensor[source]#
Transform a tensor of plateaus to a tensor of points. This is done by reshaping the data such that one dimension is the plateau length, then removing that dimension by taking the mean over it.
Example
>>> manager = WaveformManager({"plateau_length": 4, "slope_length": 2}) >>> data = torch.tensor([[1], [1], [1], [1], [5], [5], [5], [5], [3], [3], [3], [3]]) >>> manager.plateaus_to_points(data) torch.tensor([[1], [5], [3]])
In this example we have 3 plateaus of length 4.
- Parameters:
data (torch.Tensor) – The input data, should consist of sequences of repeated numbers, each sequence having the lenght of the set plateau length of the object.
- Returns:
output – Tensor where every plateau of the input data is represented by a single point.
- Return type:
torch.Tensor
- Raises:
AssertionError – If the lenght of the input data is not a multiple of the plateau length of the object.
- plateaus_to_waveform(data: Tensor, return_pytorch=True) Tuple[ndarray | Tensor, List[bool] | Tensor][source]#
Transform plateau data into full waveform data by adding slopes inbetween the plateaus. Creates new array and alternates between adding slopes and plateaus. Simultaneously makes a mask that indicates the positions of the plateaus. Will throw error if data size is not multiple of set plateau length of the object (self.plateau_length).
Example
>>> manager = WaveformManager({"plateau_length": 2, "slope_length": 2}) >>> data = torch.tensor([[1], [1], [3], [3]]) >>> manager.plateaus_to_waveform(data) (torch.tensor([[0], [1], [1], [1], [1], [3], [3], [3], [3], [0]]), torch.tensor([False, False, True, True, False, False, True, True, False, False])
In this example we have 2 plateaus of length 2, which is also the length of our waveform object. Transforming to waveforms with slope length 2 adds a plateau of length 2 inbetween each of the 2 plateaus.
- Parameters:
data (torch.Tensor) – The input data, should consist of sequences of repeated numbers, each sequence having the same length of the set plateau length of the object.
return_pytorch (bool, optional) – Indicates whether to return a pytorch tensor (true) or a numpy array (false). Default is true.
- Returns:
output_data (torch.Tensor or np.array) – The plateau data with the added slopes.
output_mask (List[bool] or torch.Tensor) – The resulting mask - list of booleans with true at plateaus and false at slopes (or a 1D tensor).
- Raises:
AssertionError – If the lenght of the input data is not a multiple of the plateau length of the object.
- points_to_plateaus(data)[source]#
Generates plateaus for the points inputted
- Parameters:
data (torch.tensor) – points for which plateaus are generated
- Returns:
plateaus generated from points as a torch tensor
- Return type:
torch.tensor
Example
waveform_mgr = WaveformManager(configs) data = (1,1) points = torch.rand(data) plateaus = waveform_mgr.points_to_pleateaus(points)
- points_to_waveform(data)[source]#
Generates a waveform (voltage input over time) with constant intervals of value amplitudes[i] for interval i of length[i].
- Parameters:
data (torch.tensor) – points for which waveform is generated as a torch tensor
- Returns:
the generated waveworm torch tesnor
- Return type:
torch.tensor
Example
waveform_mgr = WaveformManager(configs) data = (1,1) points = torch.rand(data) waveform = waveform_mgr.points_to_waveform(points)
- waveform_to_plateaus(data: Tensor, mask=None) Tensor[source]#
Go from waveform to only plateaus by removing the slopes. Either generate a mask or use a given one.
Assume input data is infact a waveform (no size assertion).
Example
>>> manager = WaveformManager({"plateau_length": 2, "slope_length": 2}) >>> data = torch.tensor([[0], [1], [1], [1], [1], [5], [5], [5], [5], [0]]) >>> manager.waveform_to_plateaus(data) torch.tensor([[1], [1], [5], [5]])
- Parameters:
data (torch.Tensor) – Input data in waveform form.
mask (Sequence[bool], optional) – Provide a mask, by default None
- Returns:
Tensor with the slopes removed.
- Return type:
torch.Tensor
- waveform_to_points(data: Tensor, mask=None) Tensor[source]#
Transform waveform data to point data. First apply a mask to remove the slopes, then apply self.plateaus_to_points to get only points. If a mask is not given, it will be generated.
Example
>>> manager = WaveformManager({"plateau_length": 1, "slope_length": 2}) >>> data = torch.tensor([[0], [1], [1], [1], [5], [5], [5], [0]]) >>> manager.waveform_to_points(data) torch.tensor([[1], [5]])
- Parameters:
data (torch.Tensor) – Input data in waveform form.
mask (Sequence[bool], optional) – Provide a mask, by default None.
- Returns:
A tensor where each data point is represented once.
- Return type:
torch.Tensor
- Raises:
AssertionError – If the lenght of the input data is not a multiple of the plateau length of the object.