Tokenizer需预清洗文本:去HTML/特殊符号、转小写;fit_on_texts前须排除None/空串;显式设filters含中文标点;pad_sequences对齐序列,post-padding更优;预训练词向量需手动构建embedding matrix;fit_on_texts必须全局一次性执行,不可放入tf.data.map。

用 tf.keras.preprocessing.text.Tokenizer 做批量分词,但得先处理好文本清洗
直接喂原始文本给 Tokenizer 很容易出问题:HTML标签、多余空格、特殊符号混在句子里,会导致生成的词表膨胀、OOV(out-of-vocabulary)比例升高。它默认只按空格和标点切分,不清理,也不小写化。
实操建议:
- 预处理用
re.sub(r'[^a-zA-Z0-9u4e00-u9fffs]', '', text)粗筛(中文需保留 u4e00-u9fff,英文数字留白) - 统一转小写:
text.lower()(英文场景必须,中文可跳过) - 避免用
fit_on_texts()传入含None或空字符串的列表——会静默跳过,但后续texts_to_sequences()可能返回空列表,引发 shape 不匹配 - 设置
filters='!"#$%&()*+,-./:;?@[\]^_`{|}~ '显式控制哪些字符被剔除(默认值不含中文标点,需手动加)
texts_to_sequences() 返回不等长序列?用 tf.keras.preprocessing.sequence.pad_sequences() 对齐
分词后每个样本是变长整数列表,无法直接进模型。不能靠自己写 for 循环 + np.pad,那样丢失梯度、且 batch 内 padding 方式难统一。
正确做法:
立即学习“Python免费学习笔记(深入)”;
- 调用
pad_sequences(sequences, maxlen=128, padding='post', truncating='post') -
maxlen要根据语料长度分布选——看np.percentile([len(s) for s in sequences], 95),别硬设 512 -
padding='post'比'pre'更友好:LSTM/GRU 类模型对末尾 pad 更鲁棒;BERT 类 tokenizer 通常要求[CLS]在开头,也更适合 post-padding - 注意返回是
numpy.ndarray,不是tf.Tensor,如需送入 tf.data pipeline,后面加tf.convert_to_tensor()
想用预训练词向量(如 GloVe)?别直接塞进 Tokenizer,要手动映射
Tokenizer 本身不加载或绑定任何嵌入矩阵,它的 word_index 是纯 ID 映射字典。如果你有 glove.6B.100d.txt,得自己构造 embedding matrix。
关键步骤:
- 读取词向量文件,构建
word2vec字典:{word: np.array(100,)} - 初始化 embedding matrix:
embedding_matrix = np.zeros((len(tokenizer.word_index) + 1, 100))(+1 是为 padding index 0 预留) - 遍历
tokenizer.word_index,对每个word查word2vec.get(word, np.zeros(100))填入对应行 - 创建 Embedding 层时传入:
Embedding(vocab_size, 100, weights=[embedding_matrix], trainable=False) - 注意:
tokenizer.word_index的索引从 1 开始,而 embedding layer 的 index 0 自动对应 padding,所以 matrix 行数必须是len(word_index)+1
用 tf.data.Dataset 流式处理大批量文本?别在 map 里调 Tokenizer.fit_on_texts()
fit_on_texts() 是一次性全局拟合操作,必须在 dataset 构建前完成。如果把它塞进 dataset.map(),每次调用都会重置词表,导致 ID 映射不一致,训练崩掉。
正确流程:
- 先用全部训练文本(或代表性子集)调一次
tokenizer.fit_on_texts(train_texts) - 保存 tokenizer:
import pickle; pickle.dump(tokenizer, open('tokenizer.pkl', 'wb')) - 构建
tf.data.Dataset后,在map中只调texts_to_sequences+pad_sequences(注意后者不能直接进 map,得用tf.py_function包一层,或提前 pad 好) - 更稳的做法:分批预处理好序列和 label,存成
.tfrecord,再用tf.data.TFRecordDataset加载
真正麻烦的是长尾分布——几千个文档里可能有上百种编码格式、换行符、零宽空格,这些不会报错,但会让 token 数突增,pad 长度虚高。上线前务必抽样 inspect 几个 tokenizer.sequences_to_texts() 输出,看有没有乱码或异常截断。


















