def add_convolution3d(
        self,
        name,
        input_channels,
        output_channels,
        depth,
        height,
        width,
        W,
        b,
        has_bias,
        groups=1,
        stride_depth=1,
        stride_height=1,
        stride_width=1,
        dilation_width=1,
        dilation_height=1,
        dilation_depth=1,
        is_deconv=False,
        output_shape=None,
        padding_mode="valid",
        padding_front=0,
        padding_back=0,
        padding_top=0,
        padding_bottom=0,
        padding_left=0,
        padding_right=0,
        input_name="data",
        output_name="out",
    ):
        """
        Add a 3 dimensional convolution layer to the network.
        Refer to the ``Convolution3DLayerParams`` message in the specification
        (NeuralNetwork.proto) for more details.

        Parameters
        ----------

        name: str
            The name of this layer.

        input_channels: int
            Number of input channels.

        output_channels: int
            Number of filter kernels. This is equal to the number of channels in the output blob.

        depth: int
            Depth of each kernel.

        height: int
            Height of each kernel.

        width: int
            Width of each kernel.

        W: numpy.array or bytes()
            Weight of the convolution kernels. ``W`` should have shape:

            - If ``deconv`` is False:

                 ``(output_channels, kernel_channels, depth, height, width)``, where:

                 ``kernel_channels = input_channels / groups``

            - If ``deconv`` is True:

                 ``(output_channels / groups, kernel_channels, depth, height, width)``, where:

                 ``kernel_channels = input_channels``

        b: numpy.array
            Biases of the convolution kernels. ``b`` should have shape ``(outputChannels, )``.

        has_bias: boolean
            Whether bias is ignored.
            - If True, bias is not ignored.
            - If False, bias is ignored.

        groups: int
            Number of kernel groups. Input is divided into groups along the channel axis. Each
            kernel group share the same weights. Defaults to 1.

        stride_depth, stride_height, stride_width: int
            Stride along the depth, height, and width directions, respectively. Must all be positive
            integers. Defaults to 1.

        dilation_depth, dilation_width, dilation_height: int
            Dilation factors across depth, height, and width directions. Must all be positive
            integers. Defaults to 1 in each dimension.

        is_deconv: bool
            True if this is Convolution Transpose, otherwise False.

        output_shape: None or Tuple of int
            Applicable only for Deconvolution layer.
            ``None`` if Convolution.
            Tuple of length 3 if Convolution Transpose.

        padding_mode: str
            Option for the padding type and output blob shape.
            Can be ``'custom'``, ``'valid'``, or ``'same'``.
            Defaults to ``'valid'``. Case-insensitive.

        padding_front, padding_back, padding_top, padding_bottom, padding_left, padding_right: int
            Values of depth (front, back), height (top, bottom), and width (left, right) padding to
            be used. Must all be positive integers. All default to 0.

        input_name: str or list of str
            The input blob name(s) of this layer.

        output_name: str
            The output blob name of this layer.

        Depthwise convolution
                Depthwise convolution is a special case of convolution, in which:

            * ``kernel_channels = 1`` (``== input_channels / groups``)
            * ``output_channels = channel_multiplier * input_channels``
            * ``groups = input_channels``
            * ``W``: ``[Kernel_depth, Kernel_height, Kernel_width, 1, channel_multiplier * input_channels]``

        See Also
        --------
        add_convolution, add_pooling, add_activation, add_batchnorm

        """
        # Update spec version if necessary
        if self.spec and (
            not self.spec.specificationVersion
            or self.spec.specificationVersion < _SPECIFICATION_VERSION_IOS_14
        ):
            self.spec.specificationVersion = _SPECIFICATION_VERSION_IOS_14

        if isinstance(input_name, tuple):
            input_names = list(input_name)
        elif isinstance(input_name, list):
            input_names = input_name
        else:
            input_names = [input_name]

        # 3D convolution doesn't currently support 2-inputs
        if len(input_names) > 1:
            raise ValueError("3D convolution only supports 1 input.")

        spec_layer = self._add_generic_layer(name, input_names, [output_name])

        # Set the layer params
        spec_layer_params = spec_layer.convolution3d
        spec_layer_params.isDeconvolution = is_deconv
        spec_layer_params.nGroups = groups

        spec_layer_params.outputChannels = output_channels
        spec_layer_params.inputChannels = input_channels

        spec_layer_params.kernelDepth = depth
        spec_layer_params.kernelHeight = height
        spec_layer_params.kernelWidth = width

        spec_layer_params.strideDepth = stride_depth
        spec_layer_params.strideHeight = stride_height
        spec_layer_params.strideWidth = stride_width

        if is_deconv and output_shape:
            spec_layer_params.outputShape.append(output_shape[0])
            spec_layer_params.outputShape.append(output_shape[1])
            spec_layer_params.outputShape.append(output_shape[2])

        supported_padding_modes = {"CUSTOM", "VALID", "SAME"}
        if padding_mode.upper() not in supported_padding_modes:
            raise ValueError(
                "Unsupported padding mode: %s.  Must be one of %s"
                % (padding_mode, supported_padding_modes)
            )
        if padding_mode.upper() == "CUSTOM":
            spec_layer_params.customPaddingFront = padding_front
            spec_layer_params.customPaddingBack = padding_back
            spec_layer_params.customPaddingTop = padding_top
            spec_layer_params.customPaddingBottom = padding_bottom
            spec_layer_params.customPaddingLeft = padding_left
            spec_layer_params.customPaddingRight = padding_right
        spec_layer_params.paddingType = (
            _proto.NeuralNetwork_pb2.Convolution3DLayerParams.PaddingType.Value(
                padding_mode.upper()
            )
        )

        spec_layer_params.dilationDepth = dilation_depth
        spec_layer_params.dilationHeight = dilation_height
        spec_layer_params.dilationWidth = dilation_width

        # Weight alignment: MLModel Spec requires following weight arrangement:
        # is_deconv == False ==> (output_channels, kernel_channels, depth, height, width), where kernel_channel = input_channels / groups
        # is_deconv == True ==> (kernel_channels, output_channels / groups, height, width), where kernel_channel = input_channels
        if is_deconv:
            W = W.transpose((1, 0, 2, 3, 4))

        # Assign weights
        weights = spec_layer_params.weights
        weights.floatValue.extend(W.flatten())

        # Assign biases
        spec_layer_params.hasBias = has_bias
        if has_bias:
            bias = spec_layer_params.bias
            for f in range(output_channels):
                bias.floatValue.append(float(b[f]))

        return spec_layer

        Add a 3 dimensional convolution layer to the network.
        Refer to the ``Convolution3DLayerParams`` message in the specification
        (NeuralNetwork.proto) for more details.

        Parameters
        ----------

        name: str
            The name of this layer.

        input_channels: int
            Number of input channels.

        output_channels: int
            Number of filter kernels. This is equal to the number of channels in the output blob.

        depth: int
            Depth of each kernel.

        height: int
            Height of each kernel.

        width: int
            Width of each kernel.

        W: numpy.array or bytes()
            Weight of the convolution kernels. ``W`` should have shape:

            - If ``deconv`` is False:

                 ``(output_channels, kernel_channels, depth, height, width)``, where:

                 ``kernel_channels = input_channels / groups``

            - If ``deconv`` is True:

                 ``(output_channels / groups, kernel_channels, depth, height, width)``, where:

                 ``kernel_channels = input_channels``

        b: numpy.array
            Biases of the convolution kernels. ``b`` should have shape ``(outputChannels, )``.

        has_bias: boolean
            Whether bias is ignored.
            - If True, bias is not ignored.
            - If False, bias is ignored.

        groups: int
            Number of kernel groups. Input is divided into groups along the channel axis. Each
            kernel group share the same weights. Defaults to 1.

        stride_depth, stride_height, stride_width: int
            Stride along the depth, height, and width directions, respectively. Must all be positive
            integers. Defaults to 1.

        dilation_depth, dilation_width, dilation_height: int
            Dilation factors across depth, height, and width directions. Must all be positive
            integers. Defaults to 1 in each dimension.

        is_deconv: bool
            True if this is Convolution Transpose, otherwise False.

        output_shape: None or Tuple of int
            Applicable only for Deconvolution layer.
            ``None`` if Convolution.
            Tuple of length 3 if Convolution Transpose.

        padding_mode: str
            Option for the padding type and output blob shape.
            Can be ``'custom'``, ``'valid'``, or ``'same'``.
            Defaults to ``'valid'``. Case-insensitive.

        padding_front, padding_back, padding_top, padding_bottom, padding_left, padding_right: int
            Values of depth (front, back), height (top, bottom), and width (left, right) padding to
            be used. Must all be positive integers. All default to 0.

        input_name: str or list of str
            The input blob name(s) of this layer.

        output_name: str
            The output blob name of this layer.

        Depthwise convolution
                Depthwise convolution is a special case of convolution, in which:

            * ``kernel_channels = 1`` (``== input_channels / groups``)
            * ``output_channels = channel_multiplier * input_channels``
            * ``groups = input_channels``
            * ``W``: ``[Kernel_depth, Kernel_height, Kernel_width, 1, channel_multiplier * input_channels]``

        See Also
        --------
        add_convolution, add_pooling, add_activation, add_batchnorm

        
coremltools/models/neural_network/builder.py