def set_categorical_cross_entropy_loss(self, name, input):
        r"""
        Categorical Cross Entropy is used for single label categorization
        (only one category is applicable for each data point).

        Parameters
        ----------
        name: The name of the loss layer
        input: The name of the input
                The ``input`` should be a vector of length N representing the
                distribution over N categories. This must be the output of a softmax.

        Notes
        -----

        .. math::
           Loss_ {CCE}(input, target) = -\sum_{i = 1} ^ {N}(target == i) log(input[i]) = - log(input[target])
        """
        if self.spec is None:
            return

        if name in self.layer_specs:
            raise ValueError("Name %s is already used." % name)

        if input is None:
            raise ValueError("Loss Layer input must be specified")

        target = input + "_true"

        if len(self.nn_spec.layers) < 1:
            raise ValueError(
                "Loss layer (%s) cannot be attached to an empty model." % name
            )

        # validate input
        # input must be a softmax layer output
        input_validated = False
        for _, layer in enumerate(self.nn_spec.layers[::-1]):
            layer_outputs = list(layer.output)
            layer_type = layer.WhichOneof("layer")

            if input in layer_outputs and layer_type == "softmax":
                input_validated = True
                break

        if not input_validated:
            raise ValueError(
                "Categorical Cross Entropy loss layer input (%s) must be a softmax layer output."
                % input
            )

        # validate target
        output_names = [x.name for x in self.spec.description.output]
        if target in output_names:
            raise ValueError(
                "Loss layer target (%s) must not be a model output." % target
            )

        updating_classifier = False
        predicted_probabilities_name = self.spec.description.predictedProbabilitiesName
        predicted_feature_name = self.spec.description.predictedFeatureName
        if (
            self.spec.HasField("neuralNetworkClassifier")
            and input == predicted_probabilities_name
        ):
            updating_classifier = True

        loss_layer = self.nn_spec.updateParams.lossLayers.add()
        self.layers.append(name)
        self.layer_specs[name] = loss_layer
        loss_layer.name = name
        loss_layer.categoricalCrossEntropyLossLayer.input = input
        loss_layer.categoricalCrossEntropyLossLayer.target = target

        training_inputs = self.spec.description.trainingInput
        training_inputs.extend(self.spec.description.input)
        training_input = training_inputs.add()

        if updating_classifier:
            training_input.name = predicted_feature_name
            classifier_output_type = [
                x.type
                for x in self.spec.description.output
                if x.name == predicted_feature_name
            ]

            model_type = classifier_output_type[0].WhichOneof("Type")
            if model_type == "stringType":
                datatypes._set_datatype(training_input.type, datatypes.String())
            elif model_type == "int64Type":
                datatypes._set_datatype(training_input.type, datatypes.Int64())
        else:
            training_input.name = target
            datatypes._set_datatype(training_input.type, datatypes.Array(1))
            training_input.type.multiArrayType.dataType = _proto.Model_pb2.ArrayFeatureType.INT32

        print(
            "Now adding input {} as target for categorical cross-entropy loss layer.".format(
                target
            )
        )

        Categorical Cross Entropy is used for single label categorization
        (only one category is applicable for each data point).

        Parameters
        ----------
        name: The name of the loss layer
        input: The name of the input
                The ``input`` should be a vector of length N representing the
                distribution over N categories. This must be the output of a softmax.

        Notes
        -----

        .. math::
           Loss_ {CCE}(input, target) = -\sum_{i = 1} ^ {N}(target == i) log(input[i]) = - log(input[target])
        
coremltools/models/neural_network/builder.py