Пользовательская функция потерь Keras против слоя Lambda - PullRequest
1 голос
/ 25 июня 2019

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

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

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

Вот код, который показывает две вещи, которые я сделал. Я минимизировал это насколько возможно. Это фрагменты из более крупных скриптов, но части, которые не показаны, идентичны для них, и это единственные различия:

#-----------------------------------------------------
# customLoss
#-----------------------------------------------------
# Define custom loss function that compares calcukated phi
# to true
def customLoss(y_true, y_pred):

    # Calculate weighted sum of prediction
    ones = K.ones_like(y_pred[0,:])       # [1, 1, 1, 1....]   (size Nouts)
    idx  = K.cumsum(ones)                 # [1, 2, 3, 4....]   (size Nouts)
    norm = K.sum(y_pred, axis=1)          # normalization of all outputs by batch. shape is 1D array of size batch
    wavg = K.sum(idx*y_pred, axis=1)/norm # array of size batch with weighted avg. of mean in units of bins
    wavg_cm = wavg*BINSIZE + XMIN         # array of size batch with weighted avg. of mean in physical units

    # Calculate loss
    loss_wavg = K.mean(K.square(y_true[:,0] - wavg_cm), axis=-1)

    return loss_wavg

#-----------------------------------------------------
# DefineModel
#-----------------------------------------------------
# This is used to define the model. It is only called if no model
# file is found in the model_checkpoints directory.
def DefineModel():

    # Build model
    inputs = Input(shape=(height, width, 1), name='image_inputs')
    x = Flatten()(inputs)
    x = Dense( int(Nouts*5), activation='linear')(x)
    x = Dense( Nouts, activation='relu')(x)
    model = Model(inputs=inputs, outputs=[x])

    # Compile the model and print a summary of it
    opt = Adadelta(clipnorm=1.0)
    model.compile(loss=customLoss, optimizer=opt)

    return model
#-----------------------------------------------------
# MyWeightedAvg
#
# This is used by the final Lambda layer of the network.
# It defines the function for calculating the weighted
# average of the inputs from the previous layer.
#-----------------------------------------------------
def MyWeightedAvg(inputs):

    # Calculate weighted sum of inputs
    ones = K.ones_like(inputs[0,:])       # [1, 1, 1, 1....]   (size Nouts)
    idx  = K.cumsum(ones)                 # [1, 2, 3, 4....]   (size Nouts)
    norm = K.sum(inputs, axis=1)          # normalization of all outputs by batch. shape is 1D array of size batch
    wavg = K.sum(idx*inputs, axis=1)/norm # array of size batch with weighted avg. of mean in units of bins
    wavg_cm = wavg*BINSIZE + XMIN         # array of size batch with weighted avg. of mean in physical units

    return wavg_cm

#-----------------------------------------------------
# DefineModel
#-----------------------------------------------------
# This is used to define the model. It is only called if no model
# file is found in the model_checkpoints directory.
def DefineModel():

    # Build model
    inputs = Input(shape=(height, width, 1), name='image_inputs')
    x = Flatten()(inputs)
    x = Dense( int(Nouts*5), activation='linear')(x)
    x = Dense( Nouts, activation='relu')(x)
    x = Lambda(MyWeightedAvg, output_shape=(1,), name='z_output')(x)
    model = Model(inputs=inputs, outputs=[x])

    # Compile the model and print a summary of it
    opt = Adadelta(clipnorm=1.0)
    model.compile(loss='mean_squared_error', optimizer=opt)

    return model

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

1 Ответ

0 голосов
/ 25 июня 2019

Используйте keepdims=True в операциях K.sum. Это необходимо для поддержания правильной формы.

Попробуйте следующее:

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.layers import *
from tensorflow.keras.models import Model
from tensorflow.keras import backend as K

BINSIZE = 1
XMIN = 0

def weighted_avg(inputs):
    # Calculate weighted sum of inputs
    ones = K.ones_like(inputs[0,:])       # [1, 1, 1, 1....]   (size Nouts)
    idx  = K.cumsum(ones)                 # [1, 2, 3, 4....]   (size Nouts)
    norm = K.sum(inputs, axis=-1, keepdims=True)          # normalization of all outputs by batch. shape is 1D array of size batch
    wavg = K.sum(idx*inputs, axis=-1, keepdims=True)/norm # array of size batch with weighted avg. of mean in units of bins
    wavg_cm = wavg*BINSIZE + XMIN         # array of size batch with weighted avg. of mean in physical units

    return wavg_cm

def make_model():
  inp = Input(shape=(4,))
  out = Lambda(weighted_avg)(inp)
  model = Model(inp, out)
  model.compile('adam', 'mse')
  return model

model = make_model()
model.summary()

Простой тестовый код:

import numpy as np
X = np.array([
    [1, 1, 1, 1],
    [1, 0, 0, 0],
    [0, 1, 0, 0],
    [0, 0, 1, 0],
    [0, 0, 0, 1]
])
model.predict(X)

predict должен испускать вектор столбца, такой как:

array([[2.5],
       [1. ],
       [2. ],
       [3. ],
       [4. ]], dtype=float32)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...