def add_inner_product(
        self,
        name,
        W,
        b,
        input_channels,
        output_channels,
        has_bias,
        input_name,
        output_name,
        int_8_dynamic_quantize=False,
        is_quantized_weight=False,
        quantization_type="linear",
        nbits=8,
        quant_scale=None,
        quant_bias=None,
        quant_lut=None,
    ):
        """
        Add an inner product layer to the model.
        Refer to the ``InnerProductLayerParams`` message in the specification
        (NeuralNetwork.proto) for more details.

        Parameters
        ----------
        name: str
            The name of this layer.
        W: numpy.array or bytes()
            Weight matrix of shape ``(output_channels, input_channels)``.
            If ``W`` is of type ``bytes()`` (quantized), other quantization
            related arguments must be provided as well (see below).
        b: numpy.array
            Bias vector of shape: ``(output_channels, )``.
        input_channels: int
            Number of input channels.
        output_channels: int
            Number of output channels.
        has_bias: boolean
            Whether the bias vector of this layer is ignored in the spec.

            - If True, the bias vector of this layer is not ignored.
            - If False, the bias vector is ignored.

        input_name: str
            The input blob name of this layer.
        output_name: str
            The output blob name of this layer.

        Quantization arguments, used when ``W`` is of type ``bytes()``:
            int_8_dynamic_quantize: boolean
                Whether to quantize and dequantize before and after inner product, respectively.
                Expects byte weights, representing int8 values, if True.
                See NeuralNetwork.proto for other validation conditions.

            is_quantized_weight: bool, optional
                Set it to true when ``W`` is of type ``bytes()``, representing
                quantized weights, default: false.

            quantization_type: str
                When weights are quantized (that is, ``W`` is of type ``bytes()``),
                this should be either ``"linear"`` or ``"lut"``.

            nbits: int
                Should be between 1 and 8 (inclusive). Number of bits per weight
                value. Only applicable when weights are quantized.

            quant_scale: numpy.array(dtype=numpy.float32)
                scale vector to be used with linear quantization. Must be of
                length either 1 or output_channels.

            quant_bias: numpy.array(dtype=numpy.float32)
                bias vector to be used with linear quantization. Must be of
                length either 1 or output_channels.

            quant_lut: numpy.array(dtype=numpy.float32)
                the LUT (look up table) to be used with LUT quantization.
                Must be of length 2^n bits.

        See Also
        --------
        add_embedding, add_convolution, add_batched_mat_mul
        """

        spec_layer = self._add_generic_layer(name, [input_name], [output_name])
        spec_layer_params = spec_layer.innerProduct

        # Fill in the parameters
        spec_layer_params.inputChannels = input_channels
        spec_layer_params.outputChannels = output_channels
        spec_layer_params.hasBias = has_bias
        spec_layer_params.int8DynamicQuantize = int_8_dynamic_quantize

        weights = spec_layer_params.weights
        if not is_quantized_weight and isinstance(W, _np.ndarray):
            weights.floatValue.extend(W.flatten())
        else:

            _verify_quantization_arguments(
                weight=W,
                output_channels=output_channels,
                quantization_type=quantization_type,
                nbits=nbits,
                quant_scale=quant_scale,
                quant_bias=quant_bias,
                quant_lut=quant_lut,
                int_8_dynamic_quantize=int_8_dynamic_quantize,
            )

            _fill_quantized_weights(
                weights_message=weights,
                W=W,
                use_int_8=int_8_dynamic_quantize,
                quantization_type=quantization_type,
                nbits=nbits,
                quant_scale=quant_scale,
                quant_bias=quant_bias,
                quant_lut=quant_lut,
            )

        if has_bias:
            bias = spec_layer_params.bias
            bias.floatValue.extend(b.flatten())

        return spec_layer

        Add an inner product layer to the model.
        Refer to the ``InnerProductLayerParams`` message in the specification
        (NeuralNetwork.proto) for more details.

        Parameters
        ----------
        name: str
            The name of this layer.
        W: numpy.array or bytes()
            Weight matrix of shape ``(output_channels, input_channels)``.
            If ``W`` is of type ``bytes()`` (quantized), other quantization
            related arguments must be provided as well (see below).
        b: numpy.array
            Bias vector of shape: ``(output_channels, )``.
        input_channels: int
            Number of input channels.
        output_channels: int
            Number of output channels.
        has_bias: boolean
            Whether the bias vector of this layer is ignored in the spec.

            - If True, the bias vector of this layer is not ignored.
            - If False, the bias vector is ignored.

        input_name: str
            The input blob name of this layer.
        output_name: str
            The output blob name of this layer.

        Quantization arguments, used when ``W`` is of type ``bytes()``:
            int_8_dynamic_quantize: boolean
                Whether to quantize and dequantize before and after inner product, respectively.
                Expects byte weights, representing int8 values, if True.
                See NeuralNetwork.proto for other validation conditions.

            is_quantized_weight: bool, optional
                Set it to true when ``W`` is of type ``bytes()``, representing
                quantized weights, default: false.

            quantization_type: str
                When weights are quantized (that is, ``W`` is of type ``bytes()``),
                this should be either ``"linear"`` or ``"lut"``.

            nbits: int
                Should be between 1 and 8 (inclusive). Number of bits per weight
                value. Only applicable when weights are quantized.

            quant_scale: numpy.array(dtype=numpy.float32)
                scale vector to be used with linear quantization. Must be of
                length either 1 or output_channels.

            quant_bias: numpy.array(dtype=numpy.float32)
                bias vector to be used with linear quantization. Must be of
                length either 1 or output_channels.

            quant_lut: numpy.array(dtype=numpy.float32)
                the LUT (look up table) to be used with LUT quantization.
                Must be of length 2^n bits.

        See Also
        --------
        add_embedding, add_convolution, add_batched_mat_mul
        
coremltools/models/neural_network/builder.py