Keras中的自定义模型在首次运行时无法拟合

时间:2019-02-08 15:18:25

标签: tensorflow keras python-3.6

我在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

我怎样才能使模型从一开始就适合?

0 个答案:

没有答案