Слой InfogainLoss

Я хочу использовать слой потерь типа InfogainLoss в моей модели. Но у меня возникают трудности с его определением.

  1. Есть ли учебник / пример по использованию INFOGAIN_LOSS слой?

  2. Если вход для этого слоя, вероятности класса, будет выходом SOFTMAX слой, или достаточно ввести "верх" полностью связного слоя?

INFOGAIN_LOSS требуется три входа: вероятности класса, метки и матрица H, Матрица H может быть предоставлен как параметры слоя infogain_loss_param { source: "fiename" },
Предположим, у меня есть скрипт Python, который вычисляет H как numpy.array формы (L,L) с dtype='f4' (где L это количество меток в моей модели).

  1. Как я могу конвертировать мои numpy.array в binproto файл, который может быть предоставлен в виде infogain_loss_param { source } к модели?

  2. Предположим, я хочу H должен быть предоставлен в качестве третьего входа (снизу) для слоя потерь (а не в качестве параметра модели). Как я могу это сделать?
    Должен ли я определить новый слой данных, который "верх" H? Если это так, не будут ли данные этого слоя увеличиваться при каждой итерации обучения, как прирост данных обучения? Как я могу определить несколько несвязанных входных слоев "данных" и как кофе знает, как читать из пакета "данные" обучения / тестирования пакет за пакетом, а из H "Слой данных" он знает, чтобы прочитать только один раз за весь процесс обучения?

3 ответа

Решение

У меня до сих пор нет полного ответа на мой вопрос. Этот ответ охватывает только мою третью и четвертую части:
3. Как я могу преобразовать numpy.array в файл binproto:

В питоне

H = np.eye( L, dtype = 'f4' ) 
import caffe
blob = caffe.io.array_to_blobproto( H.reshape( (1,1,L,L) ) )
with open( 'infogainH.binaryproto', 'wb' ) as f :
    f.write( blob.SerializeToString() )

Теперь вы можете добавить в модель прототип INFOGAIN_LOSS слой с H в качестве параметра:

layer {
  bottom: "topOfPrevLayer"
  bottom: "label"
  top: "infoGainLoss"
  name: "infoGainLoss"
  type: "InfogainLoss"
  infogain_loss_param {
    source: "infogainH.binaryproto"
  }
}

4. Как загрузить H как часть слоя DATA

Цитирую пост Эвана Шелхамера:

В настоящее время нет способа заставить загрузочные слои загружать данные с разной скоростью. Каждый проход вперед все слои данных будут продвигаться. Тем не менее, постоянный ввод H может быть сделан путем создания входного файла lmdb / leveldb / hdf5, который является только H, поскольку слой данных будет зацикливаться и продолжать загружать тот же H. Это, очевидно, приводит к бесполезному расходу дискового ввода-вывода.


Что касается первых двух частей моего вопроса:
1. Есть ли урок / пример по использованию слоя InfogainLoss?:
Хороший пример можно найти здесь: использование InfogainLoss для устранения дисбаланса классов.

2. Должны ли входные данные этого слоя, вероятности класса, быть выходными данными слоя Softmax?
Согласно ответу Яира ответ ДА, это должен быть выход слоя Softmax (или любого другого слоя, который гарантирует, что входные значения находятся в диапазоне [0..1]).


Недавно я заметил, что с помощью "InfogainLoss" на вершине "Softmax" слой может привести к численной нестабильности. Поэтому я предлагаю объединить эти два слоя в один (очень похоже на "SoftmaxWithLoss" слой). Математика этого комбинированного слоя дана здесь. Реализация этого "комбинированного" infogainLoss + Softmax может быть найдена в этом запросе извлечения.

Слой суммирует

-log(p_i)

и поэтому значение p_i должно быть в (0, 1], чтобы иметь смысл в качестве функции потерь (в противном случае более высокие доверительные оценки приведут к более высоким потерям). Значения log(p) приведены на приведенной ниже кривой.

введите описание изображения здесь

Я не думаю, что они должны суммировать до 1, но прохождение их через слой Softmax даст оба свойства.

Так как мне пришлось искать по многим веб-сайтам, чтобы разгадать весь код, я решил поделиться своей реализацией:

Уровень Python для вычисления H-матрицы с весами для каждого класса:

import numpy as np
import caffe


class ComputeH(caffe.Layer):
    def __init__(self, p_object, *args, **kwargs):
        super(ComputeH, self).__init__(p_object, *args, **kwargs)
        self.n_classes = -1

    def setup(self, bottom, top):
        if len(bottom) != 1:
            raise Exception("Need (only) one input to compute H matrix.")

        params = eval(self.param_str)
        if 'n_classes' in params:
            self.n_classes = int(params['n_classes'])
        else:
            raise Exception('The number of classes (n_classes) must be specified.')

    def reshape(self, bottom, top):
        top[0].reshape(1, 1, self.n_classes, self.n_classes)

    def forward(self, bottom, top):
        classes, cls_num = np.unique(bottom[0].data, return_counts=True)

        if np.size(classes) != self.n_classes or self.n_classes == -1:
            raise Exception("Invalid number of classes")

        cls_num = cls_num.astype(float)

        cls_num = cls_num.max() / cls_num
        weights = cls_num / np.sum(cls_num)

        top[0].data[...] = np.diag(weights)

    def backward(self, top, propagate_down, bottom):
        pass

и соответствующая часть из train_val.prototxt:

layer {
    name: "computeH"
    bottom: "label"
    top: "H"
    type: "Python"
    python_param {
        module: "digits_python_layers"
        layer: "ComputeH"
        param_str: '{"n_classes": 7}'
    }
    exclude { stage: "deploy" }
}
layer {
  name: "loss"
  type: "InfogainLoss"
  bottom: "score"
  bottom: "label"
  bottom: "H"
  top: "loss"
  infogain_loss_param {
    axis: 1  # compute loss and probability along axis
  }
  loss_param {
      normalization: 0
  }
  exclude {
    stage: "deploy"
  }
}
Другие вопросы по тегам