代码之家  ›  专栏  ›  技术社区  ›  Archit

无法使用自定义距离函数加载带有lambda函数的keras模型

  •  2
  • Archit  · 技术社区  · 6 年前

    我正在尝试构建一个系统,使用连体LSTM模型检查句子的相似性,该模型使用曼哈顿距离作为距离函数,同时合并两个层。 我正在使用本文中的代码

    https://medium.com/mlreview/implementing-malstm-on-kaggles-quora-question-pairs-competition-8b31b0b16a07

    问题是,在我将模型构建并保存在json文件中后,由于抛出错误,我无法加载该模型

    未定义名称“指数负曼哈顿距离”

    以下是代码:

    # Model variables
    n_hidden = 50
    gradient_clipping_norm = 1.25
    batch_size = 64
    n_epoch = 5
    
    def exponent_neg_manhattan_distance(left, right):
        ''' Helper function for the similarity estimate of the LSTMs outputs'''
        return K.exp(-K.sum(K.abs(left-right), axis=1, keepdims=True))
    
    # The visible layer
    left_input = Input(shape=(max_seq_length,), dtype='int32')
    right_input = Input(shape=(max_seq_length,), dtype='int32')
    
    embedding_layer = Embedding(len(embeddings), embedding_dim, weights=[embeddings], input_length=max_seq_length, trainable=False)
    
    # Embedded version of the inputs
    encoded_left = embedding_layer(left_input)
    encoded_right = embedding_layer(right_input)
    
    # Since this is a siamese network, both sides share the same LSTM
    shared_lstm = LSTM(n_hidden)
    
    left_output = shared_lstm(encoded_left)
    right_output = shared_lstm(encoded_right)
    
    # Calculates the distance as defined by the MaLSTM model
    malstm_distance = Merge(mode=lambda x: exponent_neg_manhattan_distance(x[0], x[1]), output_shape=lambda x: (x[0][0], 1))([left_output, right_output])
    
    # Pack it all up into a model
    malstm = Model([left_input, right_input], [malstm_distance])
    
    # Adadelta optimizer, with gradient clipping by norm
    optimizer = Adadelta(clipnorm=gradient_clipping_norm)
    
    malstm.compile(loss='mean_squared_error', optimizer=optimizer, metrics=['accuracy'])
    
    # Start training
    training_start_time = time()
    
    malstm_trained = malstm.fit([X_train['left'], X_train['right']], Y_train, batch_size=batch_size, nb_epoch=n_epoch,
                                validation_data=([X_validation['left'], X_validation['right']], Y_validation))
    
    print("Training time finished.\n{} epochs in {}".format(n_epoch, datetime.timedelta(seconds=time()-training_start_time)))
    
    malstm.save('malstm.h5')
    model_json = malstm.to_json()
    
    with open ('malstm.json', 'w') as file:
        file.write(model_json)
    
    malstm.save_weights('malst_w.h5')
    

    现在,当我尝试加载模型时,我得到以下错误:

    model = model_from_json(open('malstm.json').read(), custom_objects = {"exponent_neg_manhattan_distance":exponent_neg_manhattan_distance})
    C:\Users\archi\Miniconda3\lib\site-packages\keras\engine\topology.py:1271: UserWarning: The `Merge` layer is deprecated and will be removed after 08/2017. Use instead layers from `keras.layers.merge`, e.g. `add`, `concatenate`, etc.
      return cls(**config)
    Traceback (most recent call last):
    
      File "<ipython-input-12-4c72a4db6c29>", line 1, in <module>
        model = model_from_json(open('malstm.json').read(), custom_objects = {"exponent_neg_manhattan_distance":exponent_neg_manhattan_distance})
    
      File "C:\Users\archi\Miniconda3\lib\site-packages\keras\models.py", line 349, in model_from_json
        return layer_module.deserialize(config, custom_objects=custom_objects)
    
      File "C:\Users\archi\Miniconda3\lib\site-packages\keras\layers\__init__.py", line 55, in deserialize
        printable_module_name='layer')
    
      File "C:\Users\archi\Miniconda3\lib\site-packages\keras\utils\generic_utils.py", line 144, in deserialize_keras_object
        list(custom_objects.items())))
    
      File "C:\Users\archi\Miniconda3\lib\site-packages\keras\engine\topology.py", line 2524, in from_config
        process_node(layer, node_data)
    
      File "C:\Users\archi\Miniconda3\lib\site-packages\keras\engine\topology.py", line 2483, in process_node
        layer(input_tensors, **kwargs)
    
      File "C:\Users\archi\Miniconda3\lib\site-packages\keras\engine\topology.py", line 619, in __call__
        output = self.call(inputs, **kwargs)
    
      File "C:\Users\archi\Miniconda3\lib\site-packages\keras\legacy\layers.py", line 209, in call
        return self.mode(inputs, **arguments)
    
      File "<ipython-input-19-913812c640b3>", line 28, in <lambda>
    
    NameError: name 'exponent_neg_manhattan_distance' is not defined
    

    我在网上搜索过,这个问题可能是因为使用了lambda函数。我有没有办法加载这个模型,因为它花了大量的时间来训练。任何帮助都将不胜感激!

    2 回复  |  直到 6 年前
        1
  •  2
  •   mustfkeskin    5 年前

    首先用model保存模型。拯救 然后加载自定义对象

    model.save("model_path")
    
    
    from keras.models import load_model  
    # Returns a compiled model identical to the previous one model = 
    load_model('model_path',
               custom_objects={                                  
              'RAdam':RAdam, 
              'exponent_neg_manhattan_distance':exponent_neg_manhattan_distance})
    
    
        2
  •  1
  •   nuric    6 年前

    将注释转换为答案:如果你只是在代码中再次创建网络,你就可以挽回网络的权重。错误是关于从JSON创建网络的,但让我们从以下方面进行说明:

    # ...
    # Pack it all up into a model
    malstm = Model([left_input, right_input], [malstm_distance])
    # ... you don't need compile for only predict
    # ... skip training and model saving
    # malstm.save_weights('malst_w.h5')
    malstm.load_weights('malst_w.h5')
    malstm.predict(...)
    

    现在,权重将加载到您在代码中创建的现有模型中。