В настоящее время я пытаюсь согласовать модель с двумя выходными данными: граница (двоичная классификация) и теги (классификация нескольких меток). Я работаю над постановкой проблемы НЛП и использую вложения Новостей Google.
Вывод «тегов» научился соответствовать набору данных, в то время как вывод «границы» всегда предсказывает 1. Потери, полученные из этого вывода всегда постоянна и достигает 16, в то время как другой выход начинается с 0,69 и в конечном итоге падает до 0,5.
Граничные классы вывода чрезвычайно искажены с соотношением около 1:49 ложь: истинные выборки. Итак, я добавил дополнительный вес для истинных образцов.
def create_model(size_sequence=50, size_w2v=300, size_context=3):
size_window = size_context * 2 + 1
inputs = keras.Input(shape=(size_sequence, size_w2v, size_window,))
# CNN layers
cnn_k4 = keras.layers.Conv2D(1, (4, size_w2v), activation='relu')(inputs)
cnn_k3 = keras.layers.Conv2D(1, (3, size_w2v), activation='relu')(inputs)
cnn_k2 = keras.layers.Conv2D(1, (2, size_w2v), activation='relu')(inputs)
# Join outputs
x = keras.layers.concatenate([cnn_k4, cnn_k3, cnn_k2], axis=1)
x = keras.backend.squeeze(x, axis=2)
# Run max-pool 1D
x = keras.layers.MaxPool1D(pool_size=2)(x)
# Flatten tensor
x = keras.layers.Flatten()(x)
x = tf.expand_dims(x, 1)
# Pass through LSTM
x = keras.layers.LSTM(256)(x)
# Calculate attention
w = keras.layers.Dense(256, activation='softmax')(x)
x = keras.layers.Attention()([x, w])
# Generate output
x = keras.layers.Dense(128, activation='relu')(x)
tags = keras.layers.Dense(15, activation='sigmoid')(x)
bd = keras.layers.Dense(1, activation='softmax')(tags)
# Generate model
model = keras.Model(inputs=inputs, outputs=[bd, tags])
return model
# Loss and gradient functions
_bce_loss_obj = keras.losses.BinaryCrossentropy()
def _loss(model, x, y_bd, y_tag, training, bd_wt_factor=98.5):
# Get predictions
pred_bd, pred_tag = model(x, training=training)
# Calculate weighted boundary loss
loss_bd = tf.nn.weighted_cross_entropy_with_logits(
y_bd,
tf.squeeze(pred_bd, axis=1),
pos_weight=bd_wt_factor
)
loss_bd = keras.backend.sum(loss_bd)
# Calculated tag loss
loss_tag = _bce_loss_obj(y_true=y_tag, y_pred=pred_tag)
# Return sum of losses
return loss_bd + loss_tag
def grad(model, inputs, targets_bd, targets_tag):
with tf.GradientTape() as tape:
loss_value = _loss(model, inputs, targets_bd, targets_tag, training=True)
grads = tape.gradient(loss_value, model.trainable_variables)
grads = [grad if grad is not None else tf.zeros_like(var)
for var, grad in zip(model.trainable_variables, grads)]
return loss_value, grads
# Training
datasets = []
for book in glob.glob(fs.const.PATH_TRAIN_LIB + "/*.npz"):
datasets.append(generate_dataset(book))
params = {
'lr': 1e-4,
'epochs': 10
}
optimizer = keras.optimizers.SGD(learning_rate=params['lr'])
model = create_model()
df_dict = {
'Epoch Count': [],
'Boundary FN': [],
'Boundary FP': [],
'Tag accuracy': [],
'Average loss': [],
'Epoch duration': [],
}
for epoch in range(params['epochs']):
# Metrics
epoch_duration = time.time()
epoch_bd_fn = keras.metrics.FalseNegatives()
epoch_bd_fp = keras.metrics.FalsePositives()
epoch_tag_accuracy = keras.metrics.BinaryAccuracy()
epoch_loss_avg = keras.metrics.Mean()
for book in datasets:
model.reset_states()
for x, y_bd, y_tag in book:
# Calculate and apply gradient
loss_value, grads = grad(model, x, y_bd, y_tag)
optimizer.apply_gradients(zip(grads, model.trainable_variables))
# Track loss and metrics
preds_bd, preds_tag = model(x, training=True)
preds_bd = tf.squeeze(preds_bd, 1)
epoch_bd_fn.update_state(y_bd, preds_bd)
epoch_bd_fp.update_state(y_bd, preds_bd)
epoch_tag_accuracy.update_state(y_tag, preds_tag)
epoch_loss_avg.update_state(loss_value)
# Print outputs
df_dict['Epoch Count'].append(epoch + 1)
df_dict['Boundary FN'].append(epoch_bd_fn.result().numpy())
df_dict['Boundary FP'].append(epoch_bd_fp.result().numpy())
df_dict['Tag accuracy'].append(epoch_tag_accuracy.result().numpy())
df_dict['Average loss'].append(epoch_loss_avg.result().numpy())
df_dict['Epoch duration'].append(time.time()-epoch_duration)
IPython.display.clear_output()
display(pd.DataFrame.from_dict(df_dict))