В итоге я выбрал следующее решение, которое сработало.
1) Определите пакеты в вашем фрейме данных df
с помощью столбца batch_id
, чтобы в каждом пакете Y_train
была ваша идентичная «правда наземной партии» (в моем случае, общее количество Истинных этикеток в партии). Затем вы можете передать эти экземпляры вместе в сеть. Это можно сделать с помощью генератора:
def grouper(g,x,y):
while True:
for gr in g.unique():
# this assigns indices to the entire set of values in g,
# then subsects to all the rows in which g == gr
indices = g == gr
yield (x[indices],y[indices])
# train set
train_generator = grouper(df.loc[df['set'] == 'train','batch_id'], X_train, Y_train)
# validation set
val_generator = grouper(df.loc[df['set'] == 'val','batch_id'], X_val, Y_val)
2) определить пользовательскую функцию потерь, чтобы отследить, насколько близко общее число экземпляров, предсказанных как истинные, соответствует основной истине:
def custom_delta(y_true, y_pred):
loss = K.abs(K.mean(y_true) - K.sum(y_pred))
return loss
def custom_wrapper():
def custom_loss_function(y_true, y_pred):
return custom_delta(y_true, y_pred)
return custom_loss_function
Обратите внимание, что здесь
a) Каждая метка y_true
уже уже является суммой основной истины в нашей партии (потому что у нас нет индивидуальных значений). Вот почему y_true
не суммируется;
b) K.mean
на самом деле немного излишне, чтобы извлечь единственный скаляр из этого равномерного тензора, в котором все значения y_true в каждом пакете идентичны - K.min
или K.max
также будет работать, но у меня нет не проверял, быстрее ли их производительность.
3) Используйте fit_generator
вместо fit
:
fmodel = Sequential()
# ...your layers...
# Create the loss function object using the wrapper function above
loss_ = custom_wrapper()
fmodel.compile(loss=loss_, optimizer='adam')
history1 = fmodel.fit_generator(train_generator, steps_per_epoch=total_batches,
validation_data=val_generator,
validation_steps=df.loc[encs.df['set'] == 'val','batch_id'].nunique(),
epochs=20, verbose = 2)
Таким образом, проблема в основном рассматривается как проблема контролируемого обучения, хотя и без отдельных ярлыков, что означает, что такие понятия, как истинный / ложный положительный, здесь не имеют смысла.
Этот подход не только дал мне y_pred
, который близко соответствует итоговым значениям, которые я знаю на партию. На самом деле он находит две группы (True / False), которые занимают разные части пространства параметров.