Как реализовать пользовательскую многоклассовую целевую функцию в CatBoost? - PullRequest
1 голос
/ 24 июня 2019

Я пытаюсь реализовать пользовательскую целевую функцию для мультиклассификации, следуя инструкциям в: https://catboost.ai/docs/concepts/python-usages-examples.html#custom-objective-function

Я хотел бы знать, каков ожидаемый формат градиента и матрицы Гессена, определенной в calc_ders_multi ().

Чтобы увидеть, как это работает, я попытался воспроизвести функцию потерь MultiClass, но с определенным градиентом и матрицей Гессиана программа запускается и застревает без каких-либо ошибок. Если я не определяю гессиан (return []), программа запускается без проблем.

import numpy as np
from catboost import Pool, CatBoostClassifier


class MultiClassObjective(object):
    def calc_ders_multi(self, approxes, targets, weights):
        # approxes, targets, weights are indexed containers of floats
        # (containers with only __len__ and __getitem__ defined).
        # weights parameter can be None.
        n_classes = len(approxes)
        exponents = np.exp(approxes)
        softmax = exponents / np.sum(exponents)
        targets = np.array([1 if x == targets else 0 for x in range(n_classes)])

        der1 = targets - softmax
        der2 = np.zeros((n_classes, n_classes))
        for x in range(n_classes):
            for y in range(n_classes):
                if x == y:
                    der2[x, y] = -softmax[x] * (1 - softmax[y])
                else:
                    der2[x, y] = softmax[x] * softmax[y]

        if weights is not None:
            der1 *= weights
            der2 *= weights

        return der1, der2
        # return der1, []

train_data = [[1, 4, 5, 6],
              [4, 5, 6, 7],
              [11, 20, 30, 30],
              [30, 40, 50, 60],
              [100, 300, 200, 400]]

train_labels = [0, 0, 1, 1, 2]

train_data = Pool(data=train_data , label=train_labels )

# Initialize CatBoostClassifier with custom `loss_function`
model = CatBoostClassifier(loss_function=MultiClassObjective(),
                           eval_metric="MultiClass",
                           iterations=100,
                           random_seed=0,
                           verbose=True
                          )
# Fit model
model.fit(train_data)
...