Иерархическое Я Внимание не работает в Керасе - PullRequest
0 голосов
/ 27 марта 2020

В настоящее время я пытаюсь построить модель в keras, вдохновленную HiCE (https://github.com/acbull/HiCE), где в основном вводится набор входных предложений, используется блок самообслуживания для создания представления предложения. (на основе слов) для каждого предложения, а затем для объединения каждого предложения используется другой блок самовосприятия (цель состоит в том, чтобы вывести вложение слова, оценивая слово из словаря). Однако моя модель работает очень плохо. После некоторого исследования я обнаружил, что проблема заключается во втором блоке внимания, но я не могу понять, что происходит не так. Кто-нибудь знает, где это может быть? Я использую эту реализацию преобразователя для внимания: https://github.com/CyberZHG/keras-transformer

Вот (сокращенная) версия моей модели:

context_encoder:

word_embs = np.zeros((self.vocab_size+1, self.word_emb_dim))  #MASK

largest_ind = 0
for word in self.word2id_dict:
    ind = self.word2id_dict[word]
    #print(ind)
    if ind > largest_ind:
        largest_ind = ind
    w_emb = self.word_embedding_model.wv[word]
    word_embs[ind] = w_emb

emb_layer  = EmbeddingRet(
        input_dim=self.vocab_size+1, 
        output_dim=self.word_emb_dim,
        mask_zero=True, 
        weights=[word_embs],  
        trainable=False,
        name='Encoder-Token-Embedding',
    )

emb = emb_layer(context)  

emb2 = emb[0]


encoder_embed = emb2  #Removed positional embedding instead!


sa_context_encoder = transformer.get_encoders(self.encoder_num, encoder_embed, self.head_num, self.hidden_dim) 


context_emb = SumInternal()(sa_context_encoder)

context_encoder = Model(inputs=[context], outputs=context_emb)
context_encoder.summary()
return context_encoder

полная модель:

contexts = Input(shape=(self.max_num_context, self.max_num_words_per_context, ), dtype=tf.int64) 

context_embs = TimeDistributed(self.context_encoder)(contexts)

context_embs = ZeroVectorMasker()(context_embs) #added to rebuild mask  

aggregator_encoder_out = transformer.get_encoders(self.encoder_num, context_embs, self.head_num, self.hidden_dim)

final_estimate = MeanInternal()(aggregator_encoder_out)

model = Model(inputs=[contexts], outputs=final_estimate)
model.compile(loss='mean_squared_error', optimizer='adam', metrics=[])
model.summary()

return model

пользовательские слои:

класс SumInternal (Слой):

def __init__(self, **kwargs):
    super(SumInternal, self).__init__(**kwargs)

def build(self, input_shape):
    # Create a trainable weight variable for this layer.

    super(SumInternal, self).build(input_shape)  # Be sure to call this at the end

def compute_mask(self, inputs, mask=None):

    return None  #We don't need the current masking after this step!

def call(self, x, mask):

    mask = K.cast(mask, dtype = "float32")

    mask = tf.expand_dims(mask, -1)

    masked_vecs = x * mask

    final_sum = K.sum(masked_vecs, axis=1, keepdims=False)

    return final_sum   

def compute_output_shape(self, input_shape):
    return (input_shape[0], input_shape[2])

класс MeanInternal (Слой):

def __init__(self, **kwargs):
    super(MeanInternal, self).__init__(**kwargs)

def build(self, input_shape):

    super(MeanInternal, self).build(input_shape)  # Be sure to call this at the end

def compute_mask(self, inputs, mask=None):

    return None  


def call(self, x, mask):

    mask = K.cast(mask, dtype = "float32")

    mask = tf.expand_dims(mask, -1)
    masked_vecs = x * mask      
    div = tf.count_nonzero(mask, axis=1, dtype = "float32")        
    sum = K.sum(masked_vecs, axis=1, keepdims=False)
    mean = sum / div
    return mean


def compute_output_shape(self, input_shape):
    return (input_shape[0], input_shape[2])

класс ZeroVectorMasker (Layer):

def __init__(self, **kwargs):
    super(ZeroVectorMasker, self).__init__(**kwargs)

def build(self, input_shape):
    # Create a trainable weight variable for this layer.

    super(ZeroVectorMasker, self).build(input_shape)  # Be sure to call this at the end

def compute_mask(self, inputs, mask=None):


    #calculate zero vector masks

    zero_vector_mask =  tf.not_equal(tf.count_nonzero(inputs, axis=2), 0)
    #zero_vector_mask = K.cast(zero_vector_mask, dtype = "bool")


    zero_vector_mask = tf.Print(zero_vector_mask, [zero_vector_mask], message='Value of Zero Vec Mask !!!', summarize=100) 

    return zero_vector_mask  #We don't need the current masking after this step!

def call(self, x, mask=None):

    #here we ignore the mask, the compute_mask will output the real one (based on 0 vectors inputed through here)
    print('0vec call')
    print(x)
    #print(mask)
    return x     

def compute_output_shape(self, input_shape):
    return input_shape
...