def create_variables(self, input_spaces, action_space=None): in_space = input_spaces["inputs[0]"] assert in_space.rank > 0, "ERROR: Must have input Space ({}) with rank larger 0!".format( in_space) # Create weights matrix and (maybe) biases vector. weights_shape = (in_space.shape[0], self.units) self.weights_init = Initializer.from_spec( shape=weights_shape, specification=self.weights_spec) biases_shape = (self.units, ) self.biases_init = Initializer.from_spec( shape=biases_shape, specification=self.biases_spec) # Wrapper for backend. if get_backend() == "tf": self.layer = tf.layers.Dense( units=self.units, activation=get_activation_function(self.activation, *self.activation_params), kernel_initializer=self.weights_init.initializer, use_bias=(self.biases_spec is not False), bias_initializer=(self.biases_init.initializer or tf.zeros_initializer()), trainable=(False if self.trainable is False else True), _reuse=tf.AUTO_REUSE) # Now build the layer so that its variables get created. self.layer.build(in_space.get_shape(with_batch_rank=True)) # Register the generated variables with our registry. self.register_variables(*self.layer.variables) elif get_backend() == "pytorch": # N.b. activation must be added as a separate 'layer' when assembling a network. # In features is the num of input channels. apply_bias = (self.biases_spec is not False) in_features = in_space.shape[1] if in_space.shape[ 0] == 1 else in_space.shape[0] # print("name = {}, ndim = {}, in space.shape = {}, in_features = {}, units = {}".format( # self.name, ndim, in_space.shape, in_features, self.units)) self.layer = nn.Linear( # In case there is a batch dim here due to missing preprocessing. in_features=in_features, out_features=self.units, bias=apply_bias) # Apply weight initializer if self.weights_init.initializer is not None: # Must be a callable in PyTorch self.weights_init.initializer(self.layer.weight) if apply_bias: if self.biases_spec is not None and self.biases_init.initializer is not None: self.biases_init.initializer(self.layer.bias) else: # Fill with zeros. self.layer.bias.data.fill_(0) if self.activation is not None: # Activation function will be used in apply. self.activation_fn = get_activation_function( self.activation, *self.activation_params) # Use unique scope as name. self.register_variables( PyTorchVariable(name=self.global_scope, ref=self.layer))
def _graph_fn_apply(self, inputs): """ Args: inputs (SingleDataOp): The flattened inputs to this layer. Returns: SingleDataOp: The output after passing the input through n times the residual function, then the activation function. """ if get_backend() == "tf": results = inputs # Apply the residual unit n times to the input. for i in range(self.repeats): results = self.residual_units[i].apply(results) # Then activate and add up. result = results + inputs activation_function = get_activation_function( self.activation, self.activation_params) if activation_function is not None: result = activation_function(added_with_input) # TODO: Move into util function. if hasattr(inputs, "_batch_rank"): result._batch_rank = inputs._batch_rank if hasattr(inputs, "_time_rank"): result._time_rank = inputs._time_rank return result
def _graph_fn_apply(self, *inputs): """ The actual calculation on one or more input Ops. Args: inputs (SingleDataOp): The single (non-container) input(s) to the layer. Returns: The output(s) after having pushed input(s) through the layer. """ # `self.layer` is not given: Only apply the activation function. if self.layer is None: # No activation function. if self.activation is None: return tuple(inputs) # Pass inputs through activation function. else: activation_function = get_activation_function( self.activation, self.activation_params) output = activation_function(*inputs) # TODO: Move into util function. # Add batch-/time-rank flags. output._batch_rank = 0 if self.time_major is False else 1 if self.in_space_0 and self.in_space_0.has_time_rank: output._time_rank = 0 if self.in_space_0.time_major is True else 1 return output # `self.layer` already includes activation function details. else: if get_backend() == "tf": output = self.layer.apply(*inputs) # Add batch-/time-rank flags. output._batch_rank = 0 if self.time_major is False else 1 if self.in_space_0 and self.in_space_0.has_time_rank: output._time_rank = 0 if self.in_space_0.time_major is True else 1 return output elif get_backend() == "pytorch": # Strip empty internal states: inputs = [v for v in inputs if v is not None] # PyTorch layers are called, not `applied`. # print("in net work layer: ", self.name) # print("network inputs type", type(inputs)) # import torch # for inp in inputs: # print("per input type = {} ".format(type(inp) )) # if isinstance(inp, torch.Tensor): # print("input shape = ", inp.shape) out = self.layer(*inputs) # print("layer output shape = ", out.shape) if self.activation_fn is None: return out else: # Apply activation fn. return self.activation_fn(out)
def _graph_fn_apply(self, *inputs): """ The actual calculation on one or more input Ops. Args: inputs (SingleDataOp): The single (non-container) input(s) to the layer. Returns: The output(s) after having pushed input(s) through the layer. """ # `self.layer` is not given: Only apply the activation function. if self.layer is None: # No activation function. if self.activation is None: return tuple(inputs) # Pass inputs through activation function. else: activation_function = get_activation_function( self.activation, self.activation_params) output = activation_function(*inputs) # TODO: Move into util function. # Add batch-/time-rank flags. output._batch_rank = 0 if self.time_major is False else 1 if self.in_space_0 and self.in_space_0.has_time_rank: output._time_rank = 0 if self.in_space_0.time_major is True else 1 return output # `self.layer` already includes activation function details. else: if get_backend() == "tf": output = self.layer.apply(*inputs) # Add batch-/time-rank flags. output._batch_rank = 0 if self.time_major is False else 1 if self.in_space_0 and self.in_space_0.has_time_rank: output._time_rank = 0 if self.in_space_0.time_major is True else 1 return output elif get_backend() == "pytorch": # Strip empty internal states: # Ensure inputs are float tensors. input_tensors = [] for value in inputs: if value is not None and hasattr(value, "float"): input_tensors.append(value.float()) if not input_tensors: return None # Common debug print: # print("in net work layer: ", self.name) # import torch # shapes = [] # for inp in inputs: # if hasattr(inp, "shape"): # shapes.append(inp.shape) # else: # shapes.append(type(inp)) # print("input shapes = ", shapes) # PyTorch layers are called, not `applied`. out = self.layer(*input_tensors) # print("layer output shape = ", out.shape) if self.activation_fn is None: return out else: # Apply activation fn. return self.activation_fn(out)
def create_variables(self, input_spaces, action_space=None): in_space = input_spaces["inputs[0]"] # Create kernel and biases initializers. self.kernel_init = Initializer.from_spec( shape=self.kernel_size, specification=self.kernel_spec) self.biases_init = Initializer.from_spec( shape=self.kernel_size, specification=self.biases_spec) # Wrapper for backend. if get_backend() == "tf": self.layer = tf.layers.Conv2D( filters=self.filters, kernel_size=self.kernel_size, strides=self.strides, padding=self.padding, data_format=self.data_format, activation=get_activation_function(self.activation, *self.activation_params), use_bias=(self.biases_spec is not False), kernel_initializer=self.kernel_init.initializer, bias_initializer=(self.biases_init.initializer or tf.zeros_initializer()), trainable=(False if self.trainable is False else True), _reuse=tf.AUTO_REUSE) # Now build the layer so that its variables get created. self.layer.build(in_space.get_shape(with_batch_rank=True)) # Register the generated variables with our registry. self.register_variables(*self.layer.variables) elif get_backend() == "pytorch": shape = in_space.shape num_channels = get_input_channels(shape) apply_bias = (self.biases_spec is not False) # print("Defining conv2d layer with shape = {} and channels {}".format( # shape, num_channels # )) if self.padding == "same": # N.b. there is no 'same' or 'valid' padding for PyTorch so need custom layer. self.layer = SamePaddedConv2d( in_channels=num_channels, out_channels=self.filters, # Only support square kernels. kernel_size=self.kernel_size[0], stride=self.strides, bias=apply_bias) else: self.layer = nn.Conv2d(in_channels=num_channels, out_channels=self.filters, kernel_size=self.kernel_size, stride=self.strides, padding=0, bias=apply_bias) # Apply weight initializer if self.kernel_init.initializer is not None: # Must be a callable in PyTorch self.kernel_init.initializer(self.layer.weight) if apply_bias: if self.biases_spec is not None and self.biases_init.initializer is not None: self.biases_init.initializer(self.layer.bias) else: # Fill with zeros. self.layer.bias.data.fill_(0) if self.activation is not None: # Activation function will be used in `call`. self.activation_fn = get_activation_function( self.activation, *self.activation_params) self.register_variables( PyTorchVariable(name=self.global_scope, ref=self.layer))