Пользовательская метрическая функция keras Как подать 2 результата модели в одну функцию оценки метрики - PullRequest
2 голосов
/ 24 июня 2019

У меня есть модель обнаружения объектов CNN, которая имеет две головки (выходы) с тензорными именами 'classification' и 'regression'.

Я хочу определить метрическую функцию, которая принимает оба выхода одновременно , так что он просматривает предсказания регрессии , чтобы решить, какие индексы сохранить ииспользуйте эти индексы для выбора тензоров из классификационных прогнозов и вычисления некоторой метрики.

моя текущая метрическая функция, определенная с помощью этой ссылки :

from tensorflow.python.keras.metrics import MeanMetricWrapper

class Accuracy2(MeanMetricWrapper):

    def __init__(self, name='dummyAccuracy', dtype=None):
        super(Accuracy2, self).__init__(metric_calculator_func, name, dtype=dtype)
        self.true_positives = self.add_weight(name='lol', initializer='zeros')

    @classmethod
    def from_config(cls, config):
        if 'fn' in config:
          config.pop('fn')
        return super(Accuracy2, cls).from_config(config)


    def update_state(self, y_true, y_pred, sample_weight=None):
      print("==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@===")
      print("Y-True {}".format(y_true))
      print("Y-Pred {}".format(y_pred))
      print("==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@===")

      update_ops = [self.true_positives.assign_add(1.0)]
      return tf.group(update_ops)

    def result(self):
      return self.true_positives

    def reset_states(self):
      # The state of the metric will be reset at the start of each epoch.
      self.true_positives.assign(0.)

, который я называю во время компиляции модели как:

training_model.compile(
    loss={
        'regression'    : regression_loss(),
        'classification': classification_loss()
    },
    optimizer=keras.optimizers.Adam(lr=lr, clipnorm=0.001),
    metrics=[Accuracy2()]
)

экранный журнал во время tf.estimator.train_and_evaluate is:

INFO: тензор потока: потеря= 0,0075738616, шаг = 31 (11,941 с)

INFO: тензор потока: глобальный шаг / сек: 4,51218

INFO: тензор потока: потери = 0,01015341, шаг = 36 (1,108 с)

ИНФО: тензор потока: сохранение контрольных точек для 40 в /tmp/tmpcla2n3gy/model.ckpt.

ИНФО: тензор потока: вызов model_fn.== @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ =@= Tensor ("IteratorGetNext: 1", shape = (?, 120087, 5), dtype = float32, device = / device: CPU: 0) Тензор (" regression / concat: 0 ", shape = (?,?, 4), dtype = float32) == @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ === == @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ === Тензор ("IteratorGetNext: 2", shape = (?,120087, 2), dtype = float32, device = / device: CPU: 0) Тензор («классификация / concat: 0», shape = (?,?, 1), dtype = float32) == @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ===

INFO: тензор потока: завершен вызов model_fn.

ИНФОРМАЦИЯ: тензор потока: начало оценки в 2019-06-24T08: 20: 35Z ИНФО: тензор потока: график был завершен.2019-06-24 13: 50: 36.457345: I tenorflow / core / common_runtime / gpu / gpu_device.cc: 1512] Добавление видимых устройств gpu: 0 2019-06-24 13: 50: 36.457398: I tenorflow / core / common_runtime /gpu / gpu_device.cc: 984] Соединение устройств StreamExecutor с матрицей фронта прочности 1: 2019-06-24 13: 50: 36.457419: I tenorflow / core / common_runtime / gpu / gpu_device.cc: 990] 0 2019-06-24 13: 50: 36.457425: I tenorflow / core / common_runtime / gpu / gpu_device.cc: 1003] 0: N 2019-06-24 13: 50: 36.457539: I tenorflow / core / common_runtime / gpu / gpu_device.cc: 1115] созданУстройство TensorFlow (/ job: localhost / replica: 0 / task: 0 / device: GPU: 0 с памятью 9855 МБ) -> физический GPU (device: 0, имя: GeForce RTX 2080 Ti, идентификатор шины pci: 0000: 01:00.0, вычислительные возможности: 7,5)

INFO: tenorflow: восстановление параметров из /tmp/tmpcla2n3gy/model.ckpt-40

INFO: tenorflow: запуск local_init_op.

INFO: тензор потока: завершено выполнение local_init_op.

ИНФОРМАЦИЯ: тензор потока: оценка [10/100]

ИНФОРМАЦИЯ: тензор потока: оценкаn [20/100]

INFO: тензор потока: оценка [30/100]

INFO: тензор потока: оценка [40/100]

INFO: тензор потока: оценка [50/100]

ИНФОРМАЦИЯ: тензор потока: оценка [60/100]

ИНФОРМАЦИЯ: тензор потока: оценка [70/100]

ИНФО: тензор потока: оценка [80 /100]

ИНФОРМАЦИЯ: тензор потока: оценка [90/100]

ИНФО: тензор потока: оценка [100/100]

ИНФОРМАЦИЯ: тензор потока: завершение оценки в 2019-06-24-08: 20: 44

ИНФОРМАЦИЯ: тензорный поток: диктант сохранения для глобального шага 40: _focal = 0.0016880237, _smooth_l1 = 0.0, dummyAccuracy = 100.0, global_step = 40, потеря = 0.0016880237

Эта строка:

==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@===
Tensor("IteratorGetNext:1", shape=(?, 120087, 5), dtype=float32, device=/device:CPU:0)
Tensor("regression/concat:0", shape=(?, ?, 4), dtype=float32)
==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@===
==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@===
Tensor("IteratorGetNext:2", shape=(?, 120087, 2), dtype=float32, device=/device:CPU:0)
Tensor("classification/concat:0", shape=(?, ?, 1), dtype=float32)
==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@===

показывает, что Accuracy2() вызывается два раза сначала для регрессии , затем для классификации .но я хочу, чтобы он вызывался один раз с регрессией и классификацией , поданными в него вместе

Ответы [ 3 ]

1 голос
/ 01 июля 2019

Если вам нужны оба значения y_true для метрики.

В этом случае нам нужно сгладить наши данные, чтобы мы могли объединить их в один массив. Это потребует фиксированных выходных данных.

Предположим, у вас есть regOut и classOut в качестве тензоров. Если они 2D, просто объедините их, иначе:

regOut = Flatten()(regOut) #only if regOut is 3D or more
classOut = Flatten()(classOut) #only if classOut is 3D or more

out = Concatenate()([regOut,classOut])

Сделайте модель с этим единственным выходом:

model = Model(inputs, out)

Сделайте то же самое с вашими наборами данных:

y_reg_train = y_reg_train.reshape((y_reg_train.shape[0], -1))
y_class_train = y_clas_trains.reshape((y_class_train.shape[0], -1))
y_train = np.concatenate([y_reg_train, y_class_train], axis=-1)

#same for y_val

Затем создайте метрику, которая разделяет два:

def metric(y_true, y_pred):

    reg_true = y_true[:,:flattened_size_of_reg]
    class_true = y_true[:, flattened_size_of_reg:]

    reg_pred = y_pred[:,:flattened_size_of_reg]
    class_pred = y_pred[:, flattened_size_of_reg:]

    #calculate the metric

    return value

Поезд с комбинированным выходом:

model.fit(x_train, y_train, ...)
1 голос
/ 27 июня 2019

Если вам не нужны y_true значения в этой метрике

Это уродливый ответ, но ....

Вы должны создать слой для расчета метрики длявы.Используйте Lambda:

Учитывая, что regOut и classOut являются вашими выходными тензорами, при создании модели вместо создания модели типа Model(inputs, [regOut,classOut]) вы будете:

def metricFunc(modelOutputs):
    regressionOutput = modelOutputs[0]
    classOutput = modelOuptuts[1]

    #calculate metric
    return calculatedMetric


metricTensor = Lambda(metricFunc, name='metric_layer')([regOut,classOut])

Сделать метрику выходной для модели:

model = Model(inputs, [regOut, classOut, metricTensor])

Создать фиктивную потерю и фиктивную метрику для компиляции:

def dummyLoss(true,pred):
    return K.zeros(K.shape(true)[:1])

def dummyMetric(true,pred):
    return pred

В компиляции:

model.compile(loss = [regLoss, classLoss, dummyLoss], 
              metrics={'metric_layer':dummyMetric}, 
              optimizer=...)

Это требует, чтобы вы также тренировались с фиктивным тензором для metricTensor:

model.fit(x_train, [y_reg,y_class,np.zeros(y_reg.shape[:1])], ...)
0 голосов
/ 30 июня 2019

Позвольте мне показать вам элегантный способ достичь этого.

  • Прежде всего, определите внешнюю функцию, которая обернет вашу метрику, чтобы вы могли передать свой тензор регрессии reg_out:

    def metric_func(reg_out):
        def metric(y_true, class_out):
            return your_metric(reg_out, class_out, y_true)
        return metric
    
  • Затем назовите свой тензор классификации class_out, установив аргумент name слоя, который его производит.Например:

    class_out = Dense(1, name='class_out')(something)
    
  • Наконец, установите аргумент metrics из model.compile следующим образом:

    model.compile(...,
                  metrics={'class_out': metric_func(reg_out)})
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...