from ..core import MPEnums
from ..kernel import Kernel
from ..graph import Node, Parameter
from ..containers import Tensor
from .kernel_utils import extract_init_inputs
import numpy as np
class Unary:
"""
Base class for unary arithmetic operator kernels.
Kernel to perform element-wise unary arithmetic operation on
one MindPype data container (e.g., tensor or scalar).
Parameters
----------
graph : Graph
Graph that the kernel should be added to
inA : Tensor or Scalar
Input data container
outA : Tensor or Scalar
Output data container
See Also
--------
Kernel : Base class for all kernels
AbsoluteKernel : Kernel to calculate the absolute value of a MindPype data container
LogKernel : Kernel to calculate the natural logarithm of a MindPype data container
"""
def _initialize(self, init_inputs, init_outputs, labels=None):
"""
Initialize the kernel and compute initialization data output.
Parameters
----------
init_inputs : List of Tensors or Arrays
Initialization input data container, list of length 1
init_outputs : List of Tensors or Arrays
Initialization output data container, list of length 1
labels : None
Not used, here for compatability with other kernels
"""
# get the initialization params
init_in = init_inputs[0]
init_out = init_outputs[0]
# check if initialization is needed
if init_in is None or init_out is None:
# init not needed
return
# check the init inputs are in valid data objects
accepted_inputs = (MPEnums.TENSOR,MPEnums.ARRAY,MPEnums.CIRCLE_BUFFER)
if init_in.mp_type not in accepted_inputs:
raise TypeError("Invalid initialization input type")
if init_in.mp_type != MPEnums.TENSOR:
init_in = init_in.to_tensor()
# set the output size, as needed
if init_out.virtual:
init_out.shape = init_in.shape
self._process_data([init_in], init_outputs)
[docs]
class AbsoluteKernel(Unary, Kernel):
"""
Kernel to calculate the element-wise absolute value of
one MindPype data container (i.e. tensor or scalar)
.. note::
This kernel utilizes the numpy function
:data:`absolute <numpy:numpy.absolute>`.
Parameters
----------
graph : Graph
Graph that the kernel should be added to
inA : Tensor or Scalar
Input data container
outA : Tensor or Scalar
Output data container
See Also
--------
Kernel : Base class for all kernels
Unary : Base class for all unary arithmetic operator kernels
"""
def __init__(self, graph, inA, outA):
"""Init"""
super().__init__("Absolute", MPEnums.INIT_FROM_NONE, graph)
self.inputs = [inA]
self.outputs = [outA]
def _process_data(self, inputs, outputs):
"""
Calculate the absolute value of the input data
and assign it to the output container
Parameters
----------
inputs: List of Tensors or Scalars
Input data container, list of length 1
outputs: List of Tensors or Scalars
Output data container, list of length 1
"""
outputs[0].data = np.absolute(inputs[0].data)
[docs]
@classmethod
def add_to_graph(cls, graph, inA, outA, init_input=None, init_labels=None):
"""
Factory method to create an absolute value kernel node
and add it to a graph.
Parameters
----------
graph : Graph
Graph that the kernel should be added to
inA : Tensor or Scalar
Input data container
outA : Tensor or Scalar data
Output data container
init_input : Tensor or Scalar, default=None
MindPype data container with initialization data to be
transformed and passed to downstream nodes during graph
initialization
Return
------
node : Node
Node object containing the absolute kernel and parameters
"""
# create the kernel object
k = cls(graph, inA, outA)
# create parameter objects for the input and output
params = (Parameter(inA, MPEnums.INPUT), Parameter(outA, MPEnums.OUTPUT))
# add the kernel to a generic node object
node = Node(graph, k, params)
# add the node to the graph
graph.add_node(node)
# if initialization data is provided, add it to the node
if init_input is not None:
node.add_initialization_data([init_input], init_labels)
return node
[docs]
class LogKernel(Unary, Kernel):
"""
Kernel to perform element-wise natural logarithm operation on
one MindPype data container (i.e. tensor or scalar)
.. note::
This kernel utilizes the numpy function
:data:`log <numpy:numpy.log>`.
Parameters
----------
graph : Graph
Graph that the kernel should be added to
inA : Tensor or Scalar
Input data
outA : Tensor or Scalar
Output data
"""
def __init__(self, graph, inA, outA):
"""Init"""
super().__init__("Log", MPEnums.INIT_FROM_NONE, graph)
self.inputs = [inA]
self.outputs = [outA]
def _process_data(self, inputs, outputs):
"""
Calculate the natural logarithm of the input data
and assign it to the output container
Parameters
----------
input_data : list of Tensors or Scalars
Input data container, list of length 1
output_data : Tensor or Scalar
Output data container, list of length 1
"""
outputs[0].data = np.log(inputs[0].data)
[docs]
@classmethod
def add_to_graph(cls, graph, inA, outA, init_input=None, init_labels=None):
"""
Factory method to create a log kernel node
and add it to a graph.
Parameters
----------
graph : Graph
Graph that the kernel should be added to
inA : Tensor or Scalar
Input data container
outA : Tensor or Scalar
Output data container
init_input : Tensor or Scalar, default=None
MindPype data container with initialization data to be
transformed and passed to downstream nodes during graph
initialization
init_labels : Tensor or Array, default=None
MindPype data container with initialization labels to be
passed to downstream nodes during graph initialization
Return
------
node : Node
Node object containing the log kernel and parameters
"""
# create the kernel object
k = cls(graph, inA, outA)
# create parameter objects for the input and output
params = (Parameter(inA, MPEnums.INPUT), Parameter(outA, MPEnums.OUTPUT))
# add the kernel to a generic node object
node = Node(graph, k, params)
# add the node to the graph
graph.add_node(node)
# if initialization data is provided, add it to the node
if init_input is not None:
node.add_initialization_data([init_input], init_labels)
return node
class Binary:
"""
Base class for binary arithmetic operator kernels.
Kernel to perform binary arithmetic operation on
one MindPype data container (e.g., tensor or scalar).
Numpy broadcasting rules apply.
Parameters
----------
graph : Graph
Graph that the kernel should be added to
inA : Tensor or Scalar
Input data container
inB : Tensor or Scalar
Input data container
outA : Tensor or Scalar
Output data container
See Also
--------
Kernel : Base class for all kernels
AdditionKernel : Kernel to compute sum of two MindPype data containers
DivisionKernel : Kernel to compute quotient of two MindPype data containers
MultiplicationKernel : Kernel to compute product of two MindPype data containers
SubtractionKernel : Kernel to compute difference of two MindPype data containers
"""
def _initialize(self, init_inputs, init_outputs, labels=None):
"""
Initialize the kernel and compute initialization data output.
Parameters
----------
init_inputs : List of Tensors or Arrays
Initialization input data container, list of length 2
init_outputs : List of Tensors or Arrays
Initialization output data container, list of length 1
labels : None
Not used, here for compatability with other kernels
"""
# get the initialization params
init_inA = init_inputs[0]
init_inB = init_inputs[1]
init_out = init_outputs[0]
# check if initialization is needed
if init_inA is None or init_inB is None or init_out is None:
# init not needed
return
accepted_data_inputs = (MPEnums.TENSOR, MPEnums.ARRAY,
MPEnums.CIRCLE_BUFFER, MPEnums.SCALAR)
# check the init inputs are in valid data objects
for init_obj in (init_inA, init_inB):
if init_obj.mp_type not in accepted_data_inputs:
raise TypeError("Invalid initialization input type")
# extract the data from the input
X = [None] * 2
for i, i_in in enumerate((init_inA, init_inB)):
X[i] = extract_init_inputs(i_in)
# determine output dimensions and adjust init_out shape
phony_out = X[0] + X[1]
init_out.shape = phony_out.shape
tmp_inA = Tensor.create_from_data(self.session, X[0])
tmp_inB = Tensor.create_from_data(self.session, X[1])
self._process_data([tmp_inA, tmp_inB], init_outputs)
[docs]
class AdditionKernel(Binary, Kernel):
"""
Kernel to sum two MindPype data containers together
Parameters
----------
graph : Graph
Graph that the kernel should be added to
inA : Tensor or Scalar
Input data container
inB : Tensor or Scalar
Input data container
outA : Tensor or Scalar
Output data container
See Also
--------
Kernel : Base class for all kernels
Binary : Base class for all binary arithmetic operator kernels
add_addition_node : Factory method to create an addition kernel node and add it to a graph
"""
def __init__(self, graph, inA, inB, outA):
"""Init"""
super().__init__("Addition", MPEnums.INIT_FROM_NONE, graph)
self.inputs = [inA, inB]
self.outputs = [outA]
def _process_data(self, inputs, outputs):
"""
Calculate the sum of the input data
and assign it to the output container
Parameters
----------
input_data : List of data containers
Input data containers, list of length 2
output_data : List of data containers
Output data containers, list of length 1
"""
outputs[0].data = inputs[0].data + inputs[1].data
[docs]
@classmethod
def add_to_graph(cls, graph, inA, inB, outA, init_inputs=None, init_labels=None):
"""
Factory method to create an addition kernel node
and add it to a graph
Parameters
----------
graph : Graph
Graph that the kernel should be added to
inA : Tensor or Scalar
Input data container
inB : Tensor or Scalar
Input data container
outA : Tensor or Scalar
Output data container
init_inputs : List of two Tensors or Scalars, default=None
MindPype data containers with initialization data to be
transformed and passed to downstream nodes during graph
initialization
init_labels : Tensor or Array, default=None
MindPype data container with initialization labels to be
passed to downstream nodes during graph initialization
See Also
--------
AdditionKernel : Kernel to sum two MindPype data containers together
"""
# create the kernel object
k = cls(graph, inA, inB, outA)
# create parameter objects for the input and output
params = (
Parameter(inA, MPEnums.INPUT),
Parameter(inB, MPEnums.INPUT),
Parameter(outA, MPEnums.OUTPUT),
)
# add the kernel to a generic node object
node = Node(graph, k, params)
# add the node to the graph
graph.add_node(node)
# if initialization data is provided, add it to the node
if init_inputs is not None:
node.add_initialization_data(init_inputs, init_labels)
return node
[docs]
class DivisionKernel(Binary, Kernel):
"""
Kernel to compute the quotient of two MindPype data containers
Parameters
----------
graph : Graph
Graph that the kernel should be added to
inA : Tensor or Scalar
Input containing the dividend
inB : Tensor or Scalar
Input containing the divisor
outA : Tensor or Scalar
Output data container
See Also
--------
Kernel : Base class for all kernels
Binary : Base class for all binary arithmetic operator kernels
add_division_node : Factory method to create a division kernel node and add it to a graph
"""
def __init__(self, graph, inA, inB, outA):
"""Init"""
super().__init__("Division", MPEnums.INIT_FROM_NONE, graph)
self.inputs = [inA, inB]
self.outputs = [outA]
def _process_data(self, inputs, outputs):
"""
Calculate the quotient of the input tensors
and assign it to the output container
Parameters
----------
input_data : List of data containers
Input data containers, list of length 2
output_data : List of data containers
Output data containers, list of length 1
"""
outputs[0].data = inputs[0].data / inputs[1].data
[docs]
@classmethod
def add_to_graph(cls, graph, inA, inB, outA, init_inputs=None, init_labels=None):
"""
Factory method to create a division kernel node
and add it to a graph.
Parameters
----------
graph : Graph
Graph that the kernel should be added to
inA : Tensor or Scalar
Input containing the dividend
inB : Tensor or Scalar
Input containing the divisor
outA : Tensor or Scalar
Output data container
init_inputs : List of two Tensors or Scalars, default=None
MindPype data containers with initialization data to be
transformed and passed to downstream nodes during graph
initialization
init_labels : Tensor or Array, default=None
MindPype data container with initialization labels to be
passed to downstream nodes during graph initialization
See Also
--------
DivisionKernel : Kernel to compute the quotient of two MindPype data containers
"""
# create the kernel object
k = cls(graph, inA, inB, outA)
# create parameter objects for the input and output
params = (
Parameter(inA, MPEnums.INPUT),
Parameter(inB, MPEnums.INPUT),
Parameter(outA, MPEnums.OUTPUT),
)
# add the kernel to a generic node object
node = Node(graph, k, params)
# add the node to the graph
graph.add_node(node)
# if initialization data is provided, add it to the node
if init_inputs is not None:
node.add_initialization_data(init_inputs, init_labels)
return node
[docs]
class MultiplicationKernel(Binary, Kernel):
"""
Kernel to compute the product of two MindPype data containers
.. note:: This is an element-wise multiplication operation
Parameters
----------
graph : Graph
Graph that the kernel should be added to
inA : Tensor or Scalar
Input data container
inB : Tensor or Scalar
Input data container
outA : Tensor or Scalar
Output data container
See Also
--------
Kernel : Base class for all kernels
Binary : Base class for all binary arithmetic operator kernels
add_multiplication_node : Factory method to create a multiplication kernel node and add it to a graph
"""
def __init__(self, graph, inA, inB, outA):
"""Init"""
super().__init__("Multiplication", MPEnums.INIT_FROM_NONE, graph)
self.inputs = [inA, inB]
self.outputs = [outA]
def _process_data(self, inputs, outputs):
"""
Calculate the product of the inputs
and assign it to the output container
Parameters
----------
input_data : List of data containers
Input data containers, list of length 2
output_data : List of data containers
Output data containers, list of length 1
"""
outputs[0].data = inputs[0].data * inputs[1].data
[docs]
@classmethod
def add_to_graph(cls, graph, inA, inB, outA, init_inputs=None, init_labels=None):
"""
Factory method to create a multiplication kernel node
and add it to a graph
Parameters
----------
graph : Graph
Graph that the kernel should be added to
inA : Tensor or Scalar
Input data container
inB : Tensor or Scalar
Input data container
outA : Tensor or Scalar
Output data container
init_inputs : List of two data containers, default=None
MindPype data containers with initialization data to be
transformed and passed to downstream nodes during graph
initialization
init_labels : Tensor or Array, default=None
MindPype data container with initialization labels to be
passed to downstream nodes during graph initialization
Returns
-------
node : Node
Node object that has kernel and parameter stored in it
"""
# create the kernel object
k = cls(graph, inA, inB, outA)
# create parameter objects for the input and output
params = (
Parameter(inA, MPEnums.INPUT),
Parameter(inB, MPEnums.INPUT),
Parameter(outA, MPEnums.OUTPUT),
)
# add the kernel to a generic node object
node = Node(graph, k, params)
# add the node to the graph
graph.add_node(node)
# if initialization data is provided, add it to the node
if init_inputs is not None:
node.add_initialization_data(init_inputs, init_labels)
return node
[docs]
class SubtractionKernel(Binary, Kernel):
"""
Kernel to calculate the difference between two MindPype data containers
Parameters
----------
graph : Graph
Graph that the kernel should be added to
inA : Tensor or Scalar
Input containing the minuend
inB : Tensor or Scalar
Input containing the subtrahend
outA : Tensor or Scalar
Output data container
See Also
--------
Kernel : Base class for all kernels
Binary : Base class for all binary arithmetic operator kernels
add_subtraction_node : Factory method to create a subtraction kernel node and add it to a graph
"""
def __init__(self, graph, inA, inB, outA):
"""Init"""
super().__init__("Subtraction", MPEnums.INIT_FROM_NONE, graph)
self.inputs = [inA, inB]
self.outputs = [outA]
def _process_data(self, inputs, outputs):
"""
Calculate the difference between the inputs
and assign it to the output container
Parameters
----------
input_data : List of data containers
Input data containers, list of length 2
output_data : List of data containers
Output data containers, list of length 1
"""
outputs[0].data = inputs[0].data - inputs[1].data
[docs]
@classmethod
def add_to_graph(cls, graph, inA, inB, outA, init_inputs=None, init_labels=None):
"""
Factory method to create a subtraction kernel node
and add it to a graph
Parameters
----------
graph : Graph
Graph that the kernel should be added to
inA : Tensor or Scalar
Input containing the minuend
inB : Tensor or Scalar
Input containing the subtrahend
outA : Tensor or Scalar
Output data container
init_inputs : List of two data containers, default=None
MindPype data containers with initialization data to be
transformed and passed to downstream nodes during graph
initialization
init_labels : Tensor or Array, default=None
MindPype data container with initialization labels to be
passed to downstream nodes during graph initialization
Returns
-------
node : Node
Node object that has kernel and parameter stored in it
See Also
--------
SubtractionKernel : Kernel to calculate the difference between two MindPype data containers
"""
# create the kernel object
k = cls(graph, inA, inB, outA)
# create parameter objects for the input and output
params = (
Parameter(inA, MPEnums.INPUT),
Parameter(inB, MPEnums.INPUT),
Parameter(outA, MPEnums.OUTPUT),
)
# add the kernel to a generic node object
node = Node(graph, k, params)
# add the node to the graph
graph.add_node(node)
# if initialization data is provided, add it to the node
if init_inputs is not None:
node.add_initialization_data(init_inputs, init_labels)
return node