加载pickle存储的Tokenizer调用texts_to_sequences报无analyzer属性错误
问题背景
实现序列生成逻辑时,调用generate_desc函数触发运行错误,相关代码如下:
def generate_desc(model, tokenizer, photo, max_length): # 初始化生成起始标记 in_text = 'startseq' # 逐位生成序列词 for i in range(max_length): sequence = tokenizer.texts_to_sequences([in_text])[0] # 对序列做填充对齐长度 sequence = pad_sequences([sequence], maxlen=max_length) # 预测下一个词的概率分布 yhat = model.predict([photo, sequence], verbose=0) # 取概率最大的词id yhat = argmax(yhat) # id转对应词 word = word_for_id(yhat, tokenizer) # 词不存在则终止生成 if word is None: break # 把新词拼到输入序列里,供下一轮生成 in_text += ' ' + word # 遇到结束标记则终止生成 if word == 'endseq': break return in_text
错误触发行:sequence = tokenizer.texts_to_sequences([in_text])[0]
完整报错信息:
in texts_to_sequences return list(self.texts_to_sequences_generator(texts)) in texts_to_sequences_generator if self.analyzer is None: AttributeError: 'Tokenizer' object has no attribute 'analyzer'
已知运行时使用的tokenizer对象是从pickle序列化文件加载得到。
报错原因
这个错误是典型的版本/导入路径不匹配导致的pickle序列化对象兼容问题:
- pickle序列化机制只会保存对象的实例属性,不会保存对应类的源码实现。当初保存tokenizer时,所用的Keras/TensorFlow版本中的
Tokenizer类还没有analyzer属性;加载tokenizer时,当前环境的Tokenizer类版本更新,在texts_to_sequences_generator方法里新增了对self.analyzer的判断逻辑,老版本序列化出来的实例没有这个属性,调用方法时就会抛出属性不存在的错误。 - 除了跨版本问题,如果保存tokenizer时从
tensorflow.keras路径导入Tokenizer,加载时从独立keras库路径导入(或者反过来),两个路径下的Tokenizer类实现存在差异,也会触发同类属性缺失报错。
修复方案
根据实际场景选以下任意一种方案即可:
- 方案1:对齐环境版本。把当前运行环境的TensorFlow、Keras版本调整到和当初训练、保存tokenizer时完全一致的版本,同时保证Tokenizer的导入路径和保存时完全一致,从根源上消除类实现的差异。
- 方案2:手动补全缺失属性。如果不想调整现有环境版本,加载完pickle中的tokenizer对象后,手动为其补上缺失的默认属性即可,参考代码:
import pickle # 加载序列化的tokenizer with open("你的tokenizer文件路径.pkl", "rb") as f: tokenizer = pickle.load(f) # 补全新版本Tokenizer要求的analyzer默认属性 if not hasattr(tokenizer, "analyzer"): tokenizer.analyzer = None
如果后续运行时提示其他属性缺失,直接对照当前版本Tokenizer类初始化方法的参数默认值,给实例逐个补上对应属性即可。
- 方案3:重训tokenizer。如果还保留着当初训练tokenizer用的原始文本语料,可以直接在当前环境下重新初始化Tokenizer,在原始语料上调用
fit_on_texts完成训练,再重新保存使用,这种方法完全不会有序列化兼容问题,稳定性最高。
内容的提问来源于stack exchange,提问作者Mahmoud Ragab
相关产品推荐
相关产品推荐

