keras abstract base layer for separable convolution from keras import activations from keras import constraints from keras import initializers from keras import ops from keras import regularizers from keras backend import standardizedataformat from keras layers inputspec import inputspec from keras layers layer import layer from keras ops operationutils import computeconvoutputshape from keras utils argumentvalidation import standardizepadding from keras utils argumentvalidation import standardizetuple class baseseparableconvlayer def init self rank depthmultiplier filters kernelsize strides1 paddingvalid dataformatnone dilationrate1 activationnone usebiastrue depthwiseinitializerglorotuniform pointwiseinitializerglorotuniform biasinitializerzeros depthwiseregularizernone pointwiseregularizernone biasregularizernone activityregularizernone depthwiseconstraintnone pointwiseconstraintnone biasconstraintnone trainabletrue namenone kwargs super init trainabletrainable namename activityregularizerregularizers getactivityregularizer kwargs self rank rank self depthmultiplier depthmultiplier self filters filters self kernelsize standardizetuplekernelsize rank kernelsize self strides standardizetuplestrides rank strides self dilationrate standardizetuple dilationrate rank dilationrate self padding standardizepaddingpadding self dataformat standardizedataformatdataformat self activation activations getactivation self usebias usebias self depthwiseinitializer initializers getdepthwiseinitializer self pointwiseinitializer initializers getpointwiseinitializer self biasinitializer initializers getbiasinitializer self depthwiseregularizer regularizers getdepthwiseregularizer self pointwiseregularizer regularizers getpointwiseregularizer self biasregularizer regularizers getbiasregularizer self depthwiseconstraint constraints getdepthwiseconstraint self pointwiseconstraint constraints getpointwiseconstraint self biasconstraint constraints getbiasconstraint self dataformat self dataformat self inputspec inputspecminndimself rank 2 if self depthmultiplier is not none and self depthmultiplier 0 raise valueerror invalid value for argument depthmultiplier expected a strictly positive value received fdepthmultiplierself depthmultiplier if self filters is not none and self filters 0 raise valueerror invalid value for argument filters expected a strictly fpositive value received filtersself filters if not allself kernelsize raise valueerror the argument kernelsize cannot contain 0 received fkernelsizeself kernelsize if not allself strides raise valueerror the argument strides cannot contains 0s received fstridesself strides if maxself strides 1 and maxself dilationrate 1 raise valueerror strides 1 not supported in conjunction with fdilationrate 1 received stridesself strides and fdilationrateself dilationrate def buildself inputshape if self dataformat channelslast channelaxis 1 inputchannel inputshape1 else channelaxis 1 inputchannel inputshape1 self inputspec inputspec minndimself rank 2 axeschannelaxis inputchannel depthwisekernelshape self kernelsize inputchannel self depthmultiplier pointwisekernelshape 1 self rank self depthmultiplier inputchannel self filters self depthwisekernel self addweight namedepthwisekernel shapedepthwisekernelshape initializerself depthwiseinitializer regularizerself depthwiseregularizer constraintself depthwiseconstraint trainabletrue dtypeself dtype self pointwisekernel self addweight namepointwisekernel shapepointwisekernelshape initializerself pointwiseinitializer regularizerself pointwiseregularizer constraintself pointwiseconstraint trainabletrue dtypeself dtype if self usebias self bias self addweight namebias shapeself filters initializerself biasinitializer regularizerself biasregularizer constraintself biasconstraint trainabletrue dtypeself dtype else self bias none self built true def callself inputs outputs ops separableconv inputs self depthwisekernel self pointwisekernel stridesself strides paddingself padding dilationrateself dilationrate dataformatself dataformat if self usebias if self dataformat channelslast biasshape 1 self rank 1 self filters else biasshape 1 self filters 1 self rank bias ops reshapeself bias biasshape outputs bias if self activation is not none return self activationoutputs return outputs def computeoutputshapeself inputshape return computeconvoutputshape inputshape self filters self kernelsize stridesself strides paddingself padding dataformatself dataformat dilationrateself dilationrate def getconfigself config super getconfig config update depthmultiplier self depthmultiplier filters self filters kernelsize self kernelsize strides self strides padding self padding dataformat self dataformat dilationrate self dilationrate activation activations serializeself activation usebias self usebias depthwiseinitializer initializers serialize self depthwiseinitializer pointwiseinitializer initializers serialize self pointwiseinitializer biasinitializer initializers serialize self biasinitializer depthwiseregularizer regularizers serialize self depthwiseregularizer pointwiseregularizer regularizers serialize self pointwiseregularizer biasregularizer regularizers serialize self biasregularizer activityregularizer regularizers serialize self activityregularizer depthwiseconstraint constraints serialize self depthwiseconstraint pointwiseconstraint constraints serialize self pointwiseconstraint biasconstraint constraints serializeself biasconstraint return config abstract base layer for separable convolution this layer performs a depthwise convolution that acts separately on channels followed by a pointwise convolution that mixes channels if use_bias is true and a bias initializer is provided it adds a bias vector to the output args rank int the rank of the convolution e g 2 for 2d convolution depth_multiplier the number of depthwise convolution output channels for each input channel the total number of depthwise convolution output channels will be equal to input_channel depth_multiplier filters int the dimensionality of the output space i e the number of filters in the pointwise convolution kernel_size int or tuple list of rank integers specifying the size of the depthwise convolution window strides int or tuple list of rank integers specifying the stride length of the depthwise convolution if only one int is specified the same stride size will be used for all dimensions stride value 1 is incompatible with dilation_rate 1 padding string either valid or same case insensitive valid means no padding same results in padding evenly to the left right or up down of the input when padding same and strides 1 the output has the same size as the input data_format string either channels_last or channels_first the ordering of the dimensions in the inputs channels_last corresponds to inputs with shape batch steps features while channels_first corresponds to inputs with shape batch features steps it defaults to the image_data_format value found in your keras config file at keras keras json if you never set it then it will be channels_last dilation_rate int or tuple list of rank integers specifying the dilation rate to use for dilated convolution if only one int is specified the same dilation rate will be used for all dimensions activation activation function if none no activation is applied use_bias bool if true bias will be added to the output depthwise_initializer an initializer for the depthwise convolution kernel if none then the default initializer glorot_uniform will be used pointwise_initializer an initializer for the pointwise convolution kernel if none then the default initializer glorot_uniform will be used bias_initializer an initializer for the bias vector if none the default initializer zeros will be used depthwise_regularizer optional regularizer for the depthwise convolution kernel pointwise_regularizer optional regularizer for the pointwise convolution kernel bias_regularizer optional regularizer for the bias vector activity_regularizer optional regularizer function for the output depthwise_constraint optional projection function to be applied to the depthwise kernel after being updated by an optimizer e g used for norm constraints or value constraints for layer weights the function must take as input the unprojected variable and must return the projected variable which must have the same shape pointwise_constraint optional projection function to be applied to the pointwise kernel after being updated by an optimizer bias_constraint optional projection function to be applied to the bias after being updated by an optimizer
from keras import activations
from keras import constraints
from keras import initializers
from keras import ops
from keras import regularizers
from keras.backend import standardize_data_format
from keras.layers.input_spec import InputSpec
from keras.layers.layer import Layer
from keras.ops.operation_utils import compute_conv_output_shape
from keras.utils.argument_validation import standardize_padding
from keras.utils.argument_validation import standardize_tuple


class BaseSeparableConv(Layer):
    

    def __init__(
        self,
        rank,
        depth_multiplier,
        filters,
        kernel_size,
        strides=1,
        padding="valid",
        data_format=None,
        dilation_rate=1,
        activation=None,
        use_bias=True,
        depthwise_initializer="glorot_uniform",
        pointwise_initializer="glorot_uniform",
        bias_initializer="zeros",
        depthwise_regularizer=None,
        pointwise_regularizer=None,
        bias_regularizer=None,
        activity_regularizer=None,
        depthwise_constraint=None,
        pointwise_constraint=None,
        bias_constraint=None,
        trainable=True,
        name=None,
        **kwargs,
    ):
        super().__init__(
            trainable=trainable,
            name=name,
            activity_regularizer=regularizers.get(activity_regularizer),
            **kwargs,
        )
        self.rank = rank
        self.depth_multiplier = depth_multiplier
        self.filters = filters
        self.kernel_size = standardize_tuple(kernel_size, rank, "kernel_size")
        self.strides = standardize_tuple(strides, rank, "strides")
        self.dilation_rate = standardize_tuple(
            dilation_rate, rank, "dilation_rate"
        )
        self.padding = standardize_padding(padding)
        self.data_format = standardize_data_format(data_format)
        self.activation = activations.get(activation)
        self.use_bias = use_bias
        self.depthwise_initializer = initializers.get(depthwise_initializer)
        self.pointwise_initializer = initializers.get(pointwise_initializer)
        self.bias_initializer = initializers.get(bias_initializer)
        self.depthwise_regularizer = regularizers.get(depthwise_regularizer)
        self.pointwise_regularizer = regularizers.get(pointwise_regularizer)
        self.bias_regularizer = regularizers.get(bias_regularizer)
        self.depthwise_constraint = constraints.get(depthwise_constraint)
        self.pointwise_constraint = constraints.get(pointwise_constraint)
        self.bias_constraint = constraints.get(bias_constraint)
        self.data_format = self.data_format

        self.input_spec = InputSpec(min_ndim=self.rank + 2)

        if self.depth_multiplier is not None and self.depth_multiplier <= 0:
            raise ValueError(
                "Invalid value for argument `depth_multiplier`. Expected a "
                "strictly  positive value. Received "
                f"depth_multiplier={self.depth_multiplier}."
            )

        if self.filters is not None and self.filters <= 0:
            raise ValueError(
                "Invalid value for argument `filters`. Expected a strictly "
                f"positive value. Received filters={self.filters}."
            )

        if not all(self.kernel_size):
            raise ValueError(
                "The argument `kernel_size` cannot contain 0. Received: "
                f"kernel_size={self.kernel_size}."
            )

        if not all(self.strides):
            raise ValueError(
                "The argument `strides` cannot contains 0(s). Received: "
                f"strides={self.strides}"
            )

        if max(self.strides) > 1 and max(self.dilation_rate) > 1:
            raise ValueError(
                "`strides > 1` not supported in conjunction with "
                f"`dilation_rate > 1`. Received: strides={self.strides} and "
                f"dilation_rate={self.dilation_rate}"
            )

    def build(self, input_shape):
        if self.data_format == "channels_last":
            channel_axis = -1
            input_channel = input_shape[-1]
        else:
            channel_axis = 1
            input_channel = input_shape[1]
        self.input_spec = InputSpec(
            min_ndim=self.rank + 2, axes={channel_axis: input_channel}
        )
        depthwise_kernel_shape = self.kernel_size + (
            input_channel,
            self.depth_multiplier,
        )
        pointwise_kernel_shape = (1,) * self.rank + (
            self.depth_multiplier * input_channel,
            self.filters,
        )

        self.depthwise_kernel = self.add_weight(
            name="depthwise_kernel",
            shape=depthwise_kernel_shape,
            initializer=self.depthwise_initializer,
            regularizer=self.depthwise_regularizer,
            constraint=self.depthwise_constraint,
            trainable=True,
            dtype=self.dtype,
        )
        self.pointwise_kernel = self.add_weight(
            name="pointwise_kernel",
            shape=pointwise_kernel_shape,
            initializer=self.pointwise_initializer,
            regularizer=self.pointwise_regularizer,
            constraint=self.pointwise_constraint,
            trainable=True,
            dtype=self.dtype,
        )
        if self.use_bias:
            self.bias = self.add_weight(
                name="bias",
                shape=(self.filters,),
                initializer=self.bias_initializer,
                regularizer=self.bias_regularizer,
                constraint=self.bias_constraint,
                trainable=True,
                dtype=self.dtype,
            )
        else:
            self.bias = None
        self.built = True

    def call(self, inputs):
        outputs = ops.separable_conv(
            inputs,
            self.depthwise_kernel,
            self.pointwise_kernel,
            strides=self.strides,
            padding=self.padding,
            dilation_rate=self.dilation_rate,
            data_format=self.data_format,
        )

        if self.use_bias:
            if self.data_format == "channels_last":
                bias_shape = (1,) * (self.rank + 1) + (self.filters,)
            else:
                bias_shape = (1, self.filters) + (1,) * self.rank
            bias = ops.reshape(self.bias, bias_shape)
            outputs += bias

        if self.activation is not None:
            return self.activation(outputs)
        return outputs

    def compute_output_shape(self, input_shape):
        return compute_conv_output_shape(
            input_shape,
            self.filters,
            self.kernel_size,
            strides=self.strides,
            padding=self.padding,
            data_format=self.data_format,
            dilation_rate=self.dilation_rate,
        )

    def get_config(self):
        config = super().get_config()
        config.update(
            {
                "depth_multiplier": self.depth_multiplier,
                "filters": self.filters,
                "kernel_size": self.kernel_size,
                "strides": self.strides,
                "padding": self.padding,
                "data_format": self.data_format,
                "dilation_rate": self.dilation_rate,
                "activation": activations.serialize(self.activation),
                "use_bias": self.use_bias,
                "depthwise_initializer": initializers.serialize(
                    self.depthwise_initializer
                ),
                "pointwise_initializer": initializers.serialize(
                    self.pointwise_initializer
                ),
                "bias_initializer": initializers.serialize(
                    self.bias_initializer
                ),
                "depthwise_regularizer": regularizers.serialize(
                    self.depthwise_regularizer
                ),
                "pointwise_regularizer": regularizers.serialize(
                    self.pointwise_regularizer
                ),
                "bias_regularizer": regularizers.serialize(
                    self.bias_regularizer
                ),
                "activity_regularizer": regularizers.serialize(
                    self.activity_regularizer
                ),
                "depthwise_constraint": constraints.serialize(
                    self.depthwise_constraint
                ),
                "pointwise_constraint": constraints.serialize(
                    self.pointwise_constraint
                ),
                "bias_constraint": constraints.serialize(self.bias_constraint),
            }
        )
        return config