自定义Keras层调用报错:查询Token对应向量时提示vecs不存在
处理已分词语料任务时,需给部分特定词汇的Embedding层输出添加额外特征,最终输出维度为预计算向量维度+嵌入维度。这些特定词汇的特征存储在字典中,可通过word_dict[token_idx]获取对应的token_vec。
尝试自定义Keras层实现字典查询,代码如下:
class SpecialWords(Layer): def __init__(self, words_dict, output_dim, **kwargs): super(SpecialWords, self).__init__(**kwargs) self.words_dict = words_dict self.output_dim = output_dim # pad the words_dict vectors to the output_dim shape for key in self.words_dict.keys(): vec = self.words_dict[key] self.words_dict[key] = np.pad(vec, ((0,output_dim-len(vec)),(0,0))).T def build(self, input_shape): self.words_table = self.add_weight( name='milestone_table', shape=(len(self.words_dict), self.output_dim), initializer=tf.keras.initializers.Constant(np.array(list(self.words_dict.values()))), trainable=False ) super(SpecialWords, self).build(input_shape) def call(self, inputs, **kwargs): # looks up the vectors vecs = tf.nn.embedding_lookup(self.words_table, inputs) return vecs
使用Keras函数式API编译模型时,持续报错提示call函数中的vecs不存在,模型代码:
input = Input(shape=(None, 1), dtype='int32') embedding_branch = Embedding(input_dim=N_tokens, output_dim=D_embedding+D_words)(input) external_branch = SpecialWords(words_dict=words_dict, output_dim=D_embedding+D_words)(input) merged_model = Add()([embedding_branch.output, external_branch.output])
修正模型分支调用逻辑
函数式API中,Embedding和自定义层调用后返回的是张量,而非模型对象,因此.output属性不存在,这是核心错误来源。正确写法应为:input_layer = Input(shape=(None, 1), dtype='int32') embedding_branch = Embedding(input_dim=N_tokens, output_dim=D_embedding+D_words)(input_layer) external_branch = SpecialWords(words_dict=words_dict, output_dim=D_embedding+D_words)(input_layer) merged_output = Add()([embedding_branch, external_branch]) merged_model = Model(inputs=input_layer, outputs=merged_output)修复向量填充维度错误
当前填充代码np.pad(vec, ((0,output_dim-len(vec)),(0,0))).T存在维度不匹配风险,若原vec是一维数组会直接报错,转置操作也会导致向量维度反转。修正为一维向量适配的填充逻辑:for key in self.words_dict.keys(): vec = self.words_dict[key] # 确保向量为一维 vec = np.squeeze(vec) pad_len = self.output_dim - len(vec) self.words_dict[key] = np.pad(vec, (0, pad_len), mode='constant')对齐输入输出维度
输入input是(None,1)的二维张量,tf.nn.embedding_lookup处理后维度会和标准Embedding层输出存在差异,需在call函数中统一维度:def call(self, inputs, **kwargs): # 去掉多余的最后一维 inputs = tf.squeeze(inputs, axis=-1) vecs = tf.nn.embedding_lookup(self.words_table, inputs) # 恢复维度以匹配Embedding层输出 vecs = tf.expand_dims(vecs, axis=-2) return vecs校验索引与权重表的对应关系
tf.nn.embedding_lookup是用输入整数作为索引取words_table的行,若输入的token_idx不是0到len(words_dict)-1的连续整数,会导致取错行或越界,触发底层错误。需确保words_dict的key是连续的索引值,或在build时将key映射为连续索引。验证权重表初始化形状
在build方法中添加打印,确认words_table的形状符合(len(words_dict), output_dim):print("Words table shape:", np.array(list(self.words_dict.values())).shape)
内容的提问来源于stack exchange,提问作者webb

