我在Keras中有一个自定义模型。本质上是RNN模型,每一步都会计算负采样损失,即正对数和负对数的S形。
from tensorflow.keras.layers import Input, Embedding, GRU, dot, Dense, add, concatenate, multiply, Subtract
class rnn_neg_sampling(keras.models.Model):
def __init__(self, vocab_size, dim, seq_length, num_negatives=10):
super(rnn_neg_sampling, self).__init__()
self.num_negatives = num_negatives
self.embedding_input = Embedding(
input_dim=vocab_size+1,
output_dim=dim,
mask_zero=True,
input_length=seq_length
)
self.embedding_output = Embedding(
input_dim=vocab_size+1,
output_dim=dim,
mask_zero=True,
input_length=seq_length
)
self.gru = GRU(dim, return_sequences=True)
def call(self, input):
inputs, targets, negatives = input
embedded_inputs = self.embedding_input(inputs)
# https://keras.io/layers/recurrent/#gru
gru_output = self.gru(embedded_inputs)
embedded_targets = self.embedding_output(targets)
embedded_negatives = self.embedding_output(negatives)
positive_dots = K.expand_dims(multiply([gru_output, embedded_targets]), axis=1)
negative_dots = multiply([K.repeat_elements(K.expand_dims(gru_output, axis=1),
rep=self.num_negatives,
axis=1),
embedded_negatives
])
positive_logits = K.sum(positive_dots, axis=-1)
negative_logits = -K.sum(negative_dots, axis=-1)
logits = K.concatenate([positive_logits, negative_logits], axis=1)
self.add_loss(-K.mean(K.log(K.sigmoid(logits))))
我这样创建模型:
neg_number = 3
vector_dim=10
sequence_length = 5
vocab_size = 100
ns_model = rnn_neg_sampling(vocab_size, vector_dim, sequence_length, neg_number)
数据创建如下:
X_inputs = np.random.randint(0, 5, size=(batch_size, sequence_length))
X_targets = np.random.randint(0, 5, size=(batch_size, sequence_length))
X_negatives = np.random.randint(0, 5, size=(batch_size, neg_number, sequence_length))
我这样编译并拟合它:
ns_model.compile(loss=None, optimizer='rmsprop')
history = ns_model.fit([X_inputs, X_targets, X_negatives], epochs=1)
但是,它失败并显示以下日志:
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-1343-a8447c14a3a4> in <module>
1 ns_model.compile(loss=None, optimizer='rmsprop')
----> 2 history = ns_model.fit([X_inputs, X_targets, X_negatives], epochs=1)
~/miniconda3/envs/ml.crash-course/lib/python3.6/site-packages/tensorflow/python/keras/engine/training.py in fit(self, x, y, batch_size, epochs, verbose, callbacks, validation_split, validation_data, shuffle, class_weight, sample_weight, initial_epoch, steps_per_epoch, validation_steps, validation_freq, max_queue_size, workers, use_multiprocessing, **kwargs)
966 validation_steps=validation_steps,
967 validation_freq=validation_freq,
--> 968 steps_name='steps_per_epoch')
969
970 def evaluate(self,
~/miniconda3/envs/ml.crash-course/lib/python3.6/site-packages/tensorflow/python/keras/engine/training_arrays.py in model_iteration(model, inputs, targets, sample_weights, batch_size, epochs, verbose, callbacks, val_inputs, val_targets, val_sample_weights, shuffle, initial_epoch, steps_per_epoch, validation_steps, validation_freq, mode, validation_in_fit, prepared_feed_values_from_dataset, steps_name, **kwargs)
147
148 # Get step function and loop type.
--> 149 f = _make_execution_function(model, mode)
150 use_steps = is_dataset or steps_per_epoch is not None
151 do_validation = val_inputs is not None
~/miniconda3/envs/ml.crash-course/lib/python3.6/site-packages/tensorflow/python/keras/engine/training_arrays.py in _make_execution_function(model, mode)
490 if model._distribution_strategy:
491 return distributed_training_utils._make_execution_function(model, mode)
--> 492 return model._make_execution_function(mode)
493
494
~/miniconda3/envs/ml.crash-course/lib/python3.6/site-packages/tensorflow/python/keras/engine/training.py in _make_execution_function(self, mode)
2156 def _make_execution_function(self, mode):
2157 if mode == ModeKeys.TRAIN:
-> 2158 self._make_fit_function()
2159 return self._fit_function
2160 if mode == ModeKeys.TEST:
~/miniconda3/envs/ml.crash-course/lib/python3.6/site-packages/tensorflow/python/keras/engine/training.py in _make_fit_function(self)
2099 ]
2100 self._make_train_function_helper(
-> 2101 '_fit_function', [self.total_loss] + metrics_tensors)
2102
2103 def _make_test_function_helper(self, fn_name, outputs, metric_updates=None):
AttributeError: 'rnn_neg_sampling' object has no attribute 'total_loss'
奇怪的是,如果我再次运行相同的代码段(只是第二次在ipython中启动此代码段),我将得到一个适合的模型:
ns_model.compile(loss=None, optimizer='rmsprop')
history = ns_model.fit([X_inputs, X_targets, X_negatives], epochs=1)
>>>>
W0208 15:14:44.158487 139940057085760 training.py:304] Output "output_1" missing from loss dictionary. We assume this was done on purpose. The fit and evaluate APIs will not be expecting any data to be passed to "output_1".
3/3==============================] - 6s 2s/sample - loss: 0.6930
我怎样才能使模型从一开始就适合?