Source code for deephyper.nas.operation._base

import tensorflow as tf


[docs]class Operation: """Interface of an operation. >>> import tensorflow as tf >>> from deephyper.nas.space.op import Operation >>> Operation(layer=tf.keras.layers.Dense(10)) Dense Args: layer (Layer): a ``tensorflow.keras.layers.Layer``. """ def __init__(self, layer: tf.keras.layers.Layer): assert isinstance(layer, tf.keras.layers.Layer) self.from_keras_layer = True self._layer = layer def __str__(self): return self.__repr__() def __repr__(self): if hasattr(self, "from_keras_layer"): return type(self._layer).__name__ else: try: return str(self) except Exception: return type(self).__name__
[docs] def __call__(self, tensors: list, seed: int = None, **kwargs): """ Args: tensors (list): a list of incoming tensors. Returns: tensor: an output tensor. """ if len(tensors) == 1: out = self._layer(tensors[0]) else: out = self._layer(tensors) return out
[docs] def init(self, current_node): """Preprocess the current operation."""
[docs]def operation(cls): """Dynamically creates a sub-class of Operation from a Keras layer. Args: cls (tf.keras.layers.Layer): takes a Keras layer class as input and return an operation class corresponding to this layer. """ def __init__(self, *args, **kwargs): self._args = args self._kwargs = kwargs self._layer = None def __repr__(self): return cls.__name__ def __call__(self, inputs, **kwargs): if self._layer is None: self._layer = cls(*self._args, **self._kwargs) if len(inputs) == 1: out = self._layer(inputs[0]) else: out = self._layer(inputs) return out cls_attrs = dict(__init__=__init__, __repr__=__repr__, __call__=__call__) op_class = type(cls.__name__, (Operation,), cls_attrs) return op_class
[docs]class Identity(Operation): def __init__(self): pass
[docs] def __call__(self, inputs, **kwargs): assert ( len(inputs) == 1 ), f"{type(self).__name__} as {len(inputs)} inputs when 1 is required." return inputs[0]
[docs]class Tensor(Operation): def __init__(self, tensor, *args, **kwargs): self.tensor = tensor def __str__(self): return str(self.tensor)
[docs] def __call__(self, *args, **kwargs): return self.tensor
[docs]class Zero(Operation): def __init__(self): self.tensor = [] def __str__(self): return "Zero"
[docs] def __call__(self, *args, **kwargs): return self.tensor
[docs]class Connect(Operation): """Connection node. Represents a possibility to create a connection between n1 -> n2. Args: graph (nx.DiGraph): a graph source_node (Node): source """ def __init__(self, search_space, source_node, *args, **kwargs): self.search_space = search_space self.source_node = source_node self.destin_node = None def __str__(self): if type(self.source_node) is list: if len(self.source_node) > 0: ids = str(self.source_node[0].id) for n in self.source_node[1:]: ids += "," + str(n.id) else: ids = "None" else: ids = self.source_node.id if self.destin_node is None: return f"{type(self).__name__}_{ids}->?" else: return f"{type(self).__name__}_{ids}->{self.destin_node.id}"
[docs] def init(self, current_node): """Set the connection in the search_space graph from n1 -> n2.""" self.destin_node = current_node if type(self.source_node) is list: for n in self.source_node: self.search_space.connect(n, self.destin_node) else: self.search_space.connect(self.source_node, self.destin_node)
[docs] def __call__(self, value, *args, **kwargs): return value