keras base class for depthwise convolution layers 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 basedepthwiseconvlayer def init self rank depthmultiplier kernelsize strides1 paddingvalid dataformatnone dilationrate1 activationnone usebiastrue depthwiseinitializerglorotuniform biasinitializerzeros depthwiseregularizernone biasregularizernone activityregularizernone depthwiseconstraintnone biasconstraintnone trainabletrue namenone kwargs super init trainabletrainable namename activityregularizerregularizers getactivityregularizer kwargs self rank rank self depthmultiplier depthmultiplier 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 biasinitializer initializers getbiasinitializer self depthwiseregularizer regularizers getdepthwiseregularizer self biasregularizer regularizers getbiasregularizer self depthwiseconstraint constraints getdepthwiseconstraint self biasconstraint constraints getbiasconstraint self inputspec inputspecminndimself rank 2 self dataformat self dataformat 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 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 0 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 depthwiseshape self kernelsize inputchannel self depthmultiplier self kernel self addweight namekernel shapedepthwiseshape initializerself depthwiseinitializer regularizerself depthwiseregularizer constraintself depthwiseconstraint trainabletrue dtypeself dtype if self usebias self bias self addweight namebias shapeself depthmultiplier inputchannel initializerself biasinitializer regularizerself biasregularizer constraintself biasconstraint trainabletrue dtypeself dtype else self bias none self built true def getinputchannelself inputshape if self dataformat channelslast inputchannel inputshape1 else inputchannel inputshape1 return inputchannel def callself inputs inputchannel self getinputchannelinputs shape outputs ops depthwiseconv inputs self kernel stridesself strides paddingself padding dilationrateself dilationrate dataformatself dataformat if self usebias if self dataformat channelslast biasshape 1 self rank 1 self depthmultiplier inputchannel else biasshape 1 self depthmultiplier inputchannel 1 self rank bias ops reshapeself bias biasshape outputs bias if self activation is not none return self activationoutputs return outputs def computeoutputshapeself inputshape inputchannel self getinputchannelinputshape return computeconvoutputshape inputshape self depthmultiplier inputchannel self kernelsize stridesself strides paddingself padding dataformatself dataformat dilationrateself dilationrate def getconfigself config super getconfig config update depthmultiplier self depthmultiplier 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 biasinitializer initializers serialize self biasinitializer depthwiseregularizer regularizers serialize self depthwiseregularizer biasregularizer regularizers serialize self biasregularizer activityregularizer regularizers serialize self activityregularizer depthwiseconstraint constraints serialize self depthwiseconstraint biasconstraint constraints serializeself biasconstraint return config abstract n d depthwise convolution layer depthwise convolution is a type of convolution in which each input channel is convolved with a different kernel called a depthwise kernel you can understand depthwise convolution as the first step in a depthwise separable convolution it is implemented via the following steps split the input into individual channels convolve each channel with an individual depthwise kernel with depth_multiplier output channels concatenate the convolved outputs along the channels axis unlike a regular convolution depthwise convolution does not mix information across different input channels the depth_multiplier argument determines how many filter are applied to one input channel as such it controls the amount of output channels that are generated per input channel in the depthwise step 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 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 strides 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 initializer for the depthwsie convolution kernel if none the default initializer glorot_uniform will be used bias_initializer initializer for the bias vector if none the default initializer zeros will be used depthwise_regularizer optional regularizer for the 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 kernel after being updated by an optimizer e g used to implement 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 constraints are not safe to use when doing asynchronous distributed training 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 BaseDepthwiseConv(Layer):
    

    def __init__(
        self,
        rank,
        depth_multiplier,
        kernel_size,
        strides=1,
        padding="valid",
        data_format=None,
        dilation_rate=1,
        activation=None,
        use_bias=True,
        depthwise_initializer="glorot_uniform",
        bias_initializer="zeros",
        depthwise_regularizer=None,
        bias_regularizer=None,
        activity_regularizer=None,
        depthwise_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.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.bias_initializer = initializers.get(bias_initializer)
        self.depthwise_regularizer = regularizers.get(depthwise_regularizer)
        self.bias_regularizer = regularizers.get(bias_regularizer)
        self.depthwise_constraint = constraints.get(depthwise_constraint)
        self.bias_constraint = constraints.get(bias_constraint)
        self.input_spec = InputSpec(min_ndim=self.rank + 2)
        self.data_format = self.data_format

        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 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. 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_shape = self.kernel_size + (
            input_channel,
            self.depth_multiplier,
        )
        self.kernel = self.add_weight(
            name="kernel",
            shape=depthwise_shape,
            initializer=self.depthwise_initializer,
            regularizer=self.depthwise_regularizer,
            constraint=self.depthwise_constraint,
            trainable=True,
            dtype=self.dtype,
        )
        if self.use_bias:
            self.bias = self.add_weight(
                name="bias",
                shape=(self.depth_multiplier * input_channel,),
                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 _get_input_channel(self, input_shape):
        if self.data_format == "channels_last":
            input_channel = input_shape[-1]
        else:
            input_channel = input_shape[1]
        return input_channel

    def call(self, inputs):
        input_channel = self._get_input_channel(inputs.shape)
        outputs = ops.depthwise_conv(
            inputs,
            self.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.depth_multiplier * input_channel,
                )
            else:
                bias_shape = (1, self.depth_multiplier * input_channel) + (
                    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):
        input_channel = self._get_input_channel(input_shape)
        return compute_conv_output_shape(
            input_shape,
            self.depth_multiplier * input_channel,
            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,
                "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
                ),
                "bias_initializer": initializers.serialize(
                    self.bias_initializer
                ),
                "depthwise_regularizer": regularizers.serialize(
                    self.depthwise_regularizer
                ),
                "bias_regularizer": regularizers.serialize(
                    self.bias_regularizer
                ),
                "activity_regularizer": regularizers.serialize(
                    self.activity_regularizer
                ),
                "depthwise_constraint": constraints.serialize(
                    self.depthwise_constraint
                ),
                "bias_constraint": constraints.serialize(self.bias_constraint),
            }
        )
        return config