У меня есть модель, которую я могу тренировать, используя пользовательскую функцию потерь, и она отлично работает. Я хотел бы заменить настраиваемую функцию потерь стандартным 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 ... и колебания близки к этому. .