керас, объединяющий две потери с регулируемыми весами, где выходы не имеют одинаковую размерность - PullRequest
0 голосов
/ 10 декабря 2018

Мой вопрос похож на заданный здесь: Керас, объединяющий две потери с регулируемыми весами

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


Вопрос:

enter image description here

У меня есть функциональная модель keras с двумя слоями с выходами x1 и x2.

x1 = Dense(1,activation='relu')(prev_inp1)

x2 = Dense(2,activation='relu')(prev_inp2)

Мне нужно использовать эти x1, а x2 использовать их в функции взвешенных потерь, как на прикрепленном изображении.Распространите «одинаковую потерю» в обе ветви.Альфа может изменяться в зависимости от итераций.

Ответы [ 2 ]

0 голосов
/ 17 декабря 2018

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

Кроме того, нам понадобится другая форма обучения, поскольку наша потеря не работает так, как другие берут только y_true и y_pred, и рассматривает возможность объединения двух разных выходов.

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

Модель прогнозирования

Давайте рассмотрим очень простой пример модели с двумя выходами и одним входом:

#any input your true model takes
inp = Input((5,5,2))

#represents the localization output
outImg = Conv2D(1,3,activation='sigmoid')(inp)

#represents the classification output
outClass = Flatten()(inp)
outClass = Dense(2,activation='sigmoid')(outClass)

#the model
predictionModel = Model(inp, [outImg,outClass])

Эта модель используется регулярно для прогнозов.Нет необходимости компилировать это.

Потери для каждой ветви

Теперь давайте создадим пользовательские функции потерь для каждой ветви, одну для LossCls и другую для LossLoc.

Используя здесь фиктивные примерыВы можете уточнить эти потери лучше, если это необходимо.Наиболее важным является то, что они выводят партии в форме (партии, 1) или (партии) .Оба выводят одну и ту же форму, поэтому их можно суммировать позже.

def calcImgLoss(x):
    true,pred = x
    loss = binary_crossentropy(true,pred)
    return K.mean(loss, axis=[1,2])

def calcClassLoss(x):
    true,pred = x
    return binary_crossentropy(true,pred)

Они будут использоваться в слоях Lambda в обучающей модели.

Слой взвешивания потерь

Теперь, давайте взвесим потери с помощью обучаемой альфы.Для обучаемых параметров требуются пользовательские слои.

class LossWeighter(Layer):
    def __init__(self, **kwargs): #kwargs can have 'name' and other things
        super(LossWeighter, self).__init__(**kwargs)

    #create the trainable weight here, notice the constraint between 0 and 1
    def build(self, inputShape):
        self.weight = self.add_weight(name='loss_weight', 
                                     shape=(1,),
                                     initializer=Constant(0.5), 
                                     constraint=Between(0,1),
                                     trainable=True)
        super(LossWeighter,self).build(inputShape)

    def call(self,inputs):
        firstLoss, secondLoss = inputs
        return (self.weight * firstLoss) + ((1-self.weight)*secondLoss)

    def compute_output_shape(self,inputShape):
        return inputShape[0]

Обратите внимание, что существует настраиваемое ограничение для сохранения этого веса между 0 и 1. Это ограничение реализовано с помощью:

class Between(Constraint):
    def __init__(self,min_value,max_value):
        self.min_value = min_value
        self.max_value = max_value

    def __call__(self,w):
        return K.clip(w,self.min_value, self.max_value)

    def get_config(self):
        return {'min_value': self.min_value,
                'max_value': self.max_value}

обучающая модель

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

def ignoreLoss(true,pred):
    return pred #this just tries to minimize the prediction without any extra computation

Входные данные модели:

#true targets
trueImg = Input((3,3,1))
trueClass = Input((2,))

#predictions from the prediction model
predImg = predictionModel.outputs[0]
predClass = predictionModel.outputs[1]

Выходные данные модели = потери:

imageLoss = Lambda(calcImgLoss, name='loss_loc')([trueImg, predImg])
classLoss = Lambda(calcClassLoss, name='loss_cls')([trueClass, predClass])
weightedLoss = LossWeighter(name='weighted_loss')([imageLoss,classLoss])

Модель:

trainingModel = Model([predictionModel.input, trueImg, trueClass], weightedLoss)
trainingModel.compile(optimizer='sgd', loss=ignoreLoss) 

Пустышка

inputImages = np.zeros((7,5,5,2))
outputImages = np.ones((7,3,3,1))
outputClasses = np.ones((7,2))
dummyOut = np.zeros((7,))

trainingModel.fit([inputImages,outputImages,outputClasses], dummyOut, epochs = 50)
predictionModel.predict(inputImages)

Необходимый импорт

from keras.layers import *
from keras.models import Model
from keras.constraints import Constraint
from keras.initializers import Constant
from keras.losses import binary_crossentropy #or another you need
0 голосов
/ 11 декабря 2018

Нет необходимости объединять ваши выводы.Чтобы передать несколько аргументов функции потерь, вы можете обернуть ее следующим образом:

def custom_loss(x1, x2, y1, y2, alpha):
    def loss(y_true, y_pred):
        return (1-alpha) * loss_cls(y1, x1) + alpha * loss_loc(y2, x2)
    return loss

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

x1 = Dense(1, activation='relu')(prev_inp1)
x2 = Dense(2, activation='relu')(prev_inp2)
y1 = Input((1,))
y2 = Input((2,))

model.compile('sgd',
              loss=custom_loss(x1, x2, y1, y2, 0.5),
              target_tensors=[y1, y2])

ПРИМЕЧАНИЕ: Не проверено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...