def __init__(self, complex_layers_spec, scope='layered-network', summary_labels=()): """ Complex Layered network. Args: complex_layers_spec: List of layer specification dicts """ super(ComplexLayeredNetwork, self).__init__(scope=scope, summary_labels=summary_labels) self.complex_layers_spec = complex_layers_spec #self.named_tensors = dict() layer_counter = Counter() for branch_spec in self.complex_layers_spec: for layer_spec in branch_spec: if isinstance(layer_spec['type'], str): name = layer_spec['type'] else: name = 'layer' scope = name + str(layer_counter[name]) layer_counter[name] += 1 layer = Layer.from_spec(spec=layer_spec, kwargs=dict( scope=scope, summary_labels=summary_labels)) # Link named dictionary reference into Layer layer.tf_tensors(named_tensors=self.named_tensors) self.add_layer(layer=layer)
def __init__(self, layers_spec, scope='layered-network', summary_labels=()): """ Layered network. Args: layers_spec: List of layer specification dicts """ super(LayeredNetwork, self).__init__(scope=scope, summary_labels=summary_labels) self.layers_spec = layers_spec layer_counter = Counter() for layer_spec in self.layers_spec: if isinstance(layer_spec['type'], str): name = layer_spec['type'] else: name = 'layer' scope = name + str(layer_counter[name]) layer_counter[name] += 1 layer = Layer.from_spec(spec=layer_spec, kwargs=dict(scope=scope, summary_labels=summary_labels)) self.add_layer(layer=layer)
def __init__(self, layers_spec, scope='layered-network', summary_labels=()): """ Layered network. Args: layers_spec: List of layer specification dicts """ super(LayeredNetwork, self).__init__(scope=scope, summary_labels=summary_labels) self.layers_spec = layers_spec layer_counter = Counter() with tf.name_scope(name=scope): for layer_spec in self.layers_spec: layer = Layer.from_spec(spec=layer_spec, kwargs=dict( scope=scope, summary_labels=summary_labels)) name = layer_spec['type'].__class__.__name__ scope = name + str(layer_counter[name]) layer_counter[name] += 1 self.add_layer(layer=layer)
def parse_layer_spec(self, layer_spec, layer_counter): if isinstance(layer_spec, list): for layer_spec in layer_spec: self.parse_layer_spec(layer_spec=layer_spec, layer_counter=layer_counter) else: if isinstance(layer_spec['type'], str): name = layer_spec['type'] else: name = 'layer' scope = name + str(layer_counter[name]) layer_counter[name] += 1 layer = Layer.from_spec( spec=layer_spec, kwargs=dict(named_tensors=self.named_tensors, scope=scope, summary_labels=self.summary_labels) ) self.add_layer(layer=layer)
def tf_apply(self, x, update): inputs_to_merge = list() for name in self.inputs: # Previous input, by name or "*", like normal network_spec # Not using named_tensors as there could be unintended outcome if name == "*" or name == "previous": inputs_to_merge.append(x) elif name in self.named_tensors: inputs_to_merge.append(self.named_tensors[name]) else: # Failed to find key in available inputs, print out help to user, raise error keys=list(self.named_tensors) raise TensorForceError( 'ComplexNetwork input "{}" doesn\'t exist, Available inputs: {}'.format(name,keys) ) # Review data for casting to more precise format so TensorFlow doesn't throw error for mixed data # Quick & Dirty cast only promote types: bool=0,int32=10, int64=20, float32=30, double=40 # cast_type_level = 0 cast_type_dict = {'bool':0, 'int32':10, 'int64':20, 'float32':30, 'float64':40} cast_type_func_dict = {0:tf.identity, 10:tf.to_int32, 20:tf.to_int64, 30:tf.to_float, 40:tf.to_double} # Scan inputs for max cast_type for tensor in inputs_to_merge: key=str(tensor.dtype.name) if key in cast_type_dict: if cast_type_dict[key] > cast_type_level: cast_type_level = cast_type_dict[key] else: raise TensorForceError('Network spec "input" doesn\'t support dtype {}'.format(keys) # Add casting if needed for index,tensor in enumerate(inputs_to_merge): key=str(tensor.dtype.name) if cast_type_dict[key] < cast_type_level: inputs_to_merge[index]=cast_type_func_dict[cast_type_level](tensor) input_tensor = tf.concat(inputs_to_merge,self.axis) return input_tensor class Output(Layer): """ Output layer. Used for ComplexLayerNetwork's to capture the tensor under and name for use with Input layers. Acts as a input to output passthrough. """ def __init__(self, output, scope='output', summary_labels=()): """ Output layer. Args: output: A string that names the tensor, will be added to available inputs """ self.output = output super(Output, self).__init__(scope=scope, summary_labels=summary_labels) def tf_apply(self, x, update): self.named_tensors[self.output]=x return x class ComplexLayeredNetwork(LayerBasedNetwork): """ Complex Network consisting of a sequence of layers, which can be created from a specification dict. """ def __init__(self, complex_layers_spec, scope='layered-network', summary_labels=()): """ Complex Layered network. Args: complex_layers_spec: List of layer specification dicts """ super(ComplexLayeredNetwork, self).__init__(scope=scope, summary_labels=summary_labels) self.complex_layers_spec = complex_layers_spec self.Inputs = dict() layer_counter = Counter() for branch_spec in self.complex_layers_spec: for layer_spec in branch_spec: if isinstance(layer_spec['type'], str): name = layer_spec['type'] else: name = 'layer' scope = name + str(layer_counter[name]) layer_counter[name] += 1 layer = Layer.from_spec( spec=layer_spec, kwargs=dict(scope=scope, summary_labels=summary_labels) ) # Link named dictionary reference into Layer layer.tf_tensors(named_tensors=self.Inputs) self.add_layer(layer=layer) def tf_apply(self, x, internals, update, return_internals=False): if isinstance(x, dict): self.Inputs.update(x) if len(x) == 1: x = next(iter(x.values())) internal_outputs = list() index = 0 for layer in self.layers: layer_internals = [internals[index + n] for n in range(layer.num_internals)] index += layer.num_internals x = layer.apply(x, update, *layer_internals) if not isinstance(x, tf.Tensor): internal_outputs.extend(x[1]) x = x[0] if return_internals: return x, internal_outputs else: return x @staticmethod def from_json(filename): # TODO: NOT TESTED """ Creates a complex_layered_network_builder from a JSON. Args: filename: Path to configuration Returns: A ComplexLayeredNetwork class with layers generated from the JSON """ path = os.path.join(os.getcwd(), filename) with open(path, 'r') as fp: config = json.load(fp=fp) return ComplexLayeredNetwork(layers_spec=config)