def call(self, inputs): inputs, activation = inputs # 1. space to batch batched = cl.space_to_batch_nd(inputs, self.kernel_size, self.strides) activation = cl.space_to_batch_nd(activation, self.kernel_size, self.strides) # 2. transforming vote = self.transforming(batched) # 3. routing pose, activation = self.routing(vote, activation) return pose, activation
def call(self, inputs): inputs, activation = inputs # 1. space to batch # patching everything into [batch_size, out_height, out_width, in_channels] + in_caps_dims (batched) # and [batch_size, out_height, out_width, in_channels] (activation). batched = cl.space_to_batch_nd(inputs, self.kernel_size, self.strides) activation = cl.space_to_batch_nd(activation, self.kernel_size, self.strides) # 2. transforming # transforming to [batch_size, out_height, out_width, in_channels, out_channels/filters] + out_caps_dims vote = self.transforming(batched) # 3. routing pose, activation = self.routing(vote, activation) return pose, activation
def conv2d(inputs, activation, filters, out_caps_dims, kernel_size, strides, padding="valid", routing_method="EMRouting", name=None, reuse=None): """A 2D convolutional capsule layer. Args: inputs: A 6-D tensor with shape [batch_size, in_height, in_width, in_channels] + in_caps_dims. activation: A 4-D tensor with shape [batch_size, in_height, in_width, in_channels]. filters: Integer, the dimensionality of the output space (i.e. the number of filters in the convolution). out_caps_dims: A tuple/list of 2 integers, specifying the dimensions of output capsule, e.g. out_caps_dims=[4, 4] representing that each output capsule has shape [4, 4]. kernel_size: An integer or tuple/list of 2 integers, specifying the height and width of the 2D convolution window. Can be a single integer to specify the same value for all spatial dimensions. strides: An integer or tuple/list of 2 integers, specifying the strides of the convolution along the height and width. Can be a single integer to specify the same value for all spatial dimensions. padding: One of "valid" or "same" (case-insensitive), now only support "valid". routing_method: One of "EMRouting" or "DynamicRouting", the method of routing-by-agreement algorithm. name: A string, the name of the layer. reuse: Boolean, whether to reuse the weights of a previous layer by the same name. Returns: pose: A 6-D tensor with shape [batch_size, out_height, out_width, out_channels] + out_caps_dims. activation: A 4-D tensor with shape [batch_size, out_height, out_width, out_channels]. """ name = "conv2d" if name is None else name with tf.variable_scope(name) as scope: if reuse: scope.reuse_variables() input_shape = cl.shape(inputs) input_rank = len(input_shape) activation_rank = len(activation.shape) if not input_rank == 6: raise ValueError('Inputs to `conv2d` should have rank 6. Received inputs rank:', str(input_rank)) if not activation_rank == 4: raise ValueError('Activation to `conv2d` should have rank 4. Received activation rank:', str(activation_rank)) if isinstance(kernel_size, int): kernel_size = [kernel_size, kernel_size, input_shape[3]] elif isinstance(kernel_size, (list, tuple)) and len(kernel_size) == 2: kernel_size = [kernel_size[0], kernel_size[1], input_shape[3]] else: raise ValueError('"kernel_size" should be an integer or tuple/list of 2 integers. Received:', str(kernel_size)) if isinstance(strides, int): strides = [strides, strides, 1] elif isinstance(strides, (list, tuple)) and len(strides) == 2: strides = [strides[0], strides[1], 1] else: raise ValueError('"strides" should be an integer or tuple/list of 2 integers. Received:', str(kernel_size)) if not isinstance(out_caps_dims, (list, tuple)) or len(out_caps_dims) != 2: raise ValueError('"out_caps_dims" should be a tuple/list of 2 integers. Received:', str(out_caps_dims)) elif isinstance(out_caps_dims, tuple): out_caps_dims = list(out_caps_dims) # 1. space to batch # patching everything into [batch_size, out_height, out_width, in_channels] + in_caps_dims (batched) # and [batch_size, out_height, out_width, in_channels] (activation). batched = cl.space_to_batch_nd(inputs, kernel_size, strides) activation = cl.space_to_batch_nd(activation, kernel_size, strides) # 2. transforming # transforming to [batch_size, out_height, out_width, in_channels, out_channels/filters] + out_caps_dims vote = transforming(batched, num_outputs=filters, out_caps_dims=out_caps_dims) # 3. routing pose, activation = routing(vote, activation, method=routing_method) return pose, activation
def conv3d(inputs, activation, filters, out_caps_dims, kernel_size, strides, padding="valid", routing_method="EMRouting", name=None, reuse=None): """A 3D convolutional capsule layer. Args: inputs: A 7-D tensor with shape [batch_size, in_depth, in_height, in_width, in_channels] + in_caps_dims. activation: A 5-D tensor with shape [batch_size, in_depth, in_height, in_width, in_channels]. filters: Integer, the dimensionality of the output space (i.e. the number of filters in the convolution). out_caps_dims: A tuple/list of 2 integers, specifying the dimensions of output capsule, e.g. out_caps_dims=[4, 4] representing that each output capsule has shape [4, 4]. kernel_size: An integer or tuple/list of 3 integers, specifying the height and width of the 3D convolution window. Can be a single integer to specify the same value for all spatial dimensions. strides: An integer or tuple/list of 3 integers, specifying the strides of the convolution along the height and width. Can be a single integer to specify the same value for all spatial dimensions. padding: One of "valid" or "same" (case-insensitive), now only support "valid". routing_method: One of "EMRouting" or "DynamicRouting", the method of routing-by-agreement algorithm. name: String, a name for the operation (optional). reuse: Boolean, whether to reuse the weights of a previous layer by the same name. Returns: pose: A 7-D tensor with shape [batch_size, out_depth, out_height, out_width, out_channels] + out_caps_dims. activation: A 5-D tensor with shape [batch_size, out_depth, out_height, out_width, out_channels]. """ name = "conv1d" if name is None else name with tf.name_scope(name): input_shape = cl.shape(inputs) input_rank = len(input_shape) activation_rank = len(activation.shape) if input_rank != 7: raise ValueError('Inputs to `conv3d` should have rank 7. Received input rank:', str(input_rank)) if activation_rank != 5: raise ValueError('Activation to `conv3d` should have rank 5. Received input shape:', str(activation_rank)) if isinstance(kernel_size, int): kernel_size = [kernel_size, kernel_size, kernel_size] elif isinstance(kernel_size, (list, tuple)) and len(kernel_size) == 3: kernel_size = kernel_size else: raise ValueError('"kernel_size" should be an integer or tuple/list of 3 integers. Received:', str(kernel_size)) if isinstance(strides, int): strides = [strides, strides, strides] elif isinstance(strides, (list, tuple)) and len(strides) == 3: strides = strides else: raise ValueError('"strides" should be an integer or tuple/list of 3 integers. Received:', str(strides)) if not isinstance(out_caps_dims, (list, tuple)) or len(out_caps_dims) != 2: raise ValueError('"out_caps_dims" should be a tuple/list of 2 integers. Received:', str(out_caps_dims)) elif isinstance(out_caps_dims, tuple): out_caps_dims = list(out_caps_dims) # 1. space to batch batched = cl.space_to_batch_nd(inputs, kernel_size, strides) activation = cl.space_to_batch_nd(activation, kernel_size, strides) # 2. transforming vote = transforming(batched, num_outputs=filters, out_caps_dims=out_caps_dims) # 3. routing pose, activation = routing(vote, activation, method=routing_method) return pose, activation