1. 为什么选择Transformer做新闻分类新闻文本分类是自然语言处理中的经典任务。过去大家常用RNN、CNN这些传统神经网络但自从Transformer横空出世局面就完全改变了。我第一次用Transformer做分类任务时准确率直接比LSTM提升了8个百分点当时就惊掉了下巴。Transformer的核心优势在于它的注意力机制。想象你在读新闻时不会平均关注每个字而是会重点看关键词。比如央行宣布降准这句话央行和降准才是重点。Transformer的self-attention机制正是模拟了这个过程它能自动学习哪些词更重要。我用一个简单例子说明注意力机制有多神奇。下面这段财经新闻美联储宣布加息50个基点导致纳斯达克指数暴跌3.2%传统模型可能平均处理每个词但Transformer会给美联储、加息、暴跌这些词更高权重。这种特性让它特别适合处理新闻文本因为新闻的关键信息往往集中在少数关键词上。2. 快速搭建Transformer分类模型2.1 数据准备我们先准备一个典型的新闻数据集包含7个类别教育科技社会时政财经房产家居每个类别1万条数据共7万条。数据质量很高已经去除了乱码和特殊符号。我从实际项目经验中发现数据清洗比模型选择更重要。曾经有个项目因为数据里有大量HTML标签导致模型效果奇差清洗后准确率直接涨了15%。数据预处理主要做三件事中文分词我用jieba去除停用词文本长度统一设为200个词import jieba from keras.preprocessing.text import Tokenizer # 加载停用词 stop_words pd.read_csv(stopwords.txt)[stopword].values # 分词函数 def cut_text(text): return .join([w for w in jieba.lcut(text) if w not in stop_words]) # 构建词表 tokenizer Tokenizer(num_words10000) tokenizer.fit_on_texts(df[cutword])2.2 模型构建我用的是Keras实现的Transformer编码器。相比原始Transformer做了两点简化只用Encoder部分分类任务不需要Decoder简化了位置编码的实现from tensorflow.keras import layers class TransformerEncoder(layers.Layer): def __init__(self, embed_dim, dense_dim, num_heads): super().__init__() self.attention layers.MultiHeadAttention(num_headsnum_heads, key_dimembed_dim) self.dense_proj keras.Sequential([ layers.Dense(dense_dim, activationrelu), layers.Dense(embed_dim) ]) self.layernorm1 layers.LayerNormalization() self.layernorm2 layers.LayerNormalization() def call(self, inputs): attn_output self.attention(inputs, inputs) proj_input self.layernorm1(inputs attn_output) proj_output self.dense_proj(proj_input) return self.layernorm2(proj_input proj_output)完整模型结构如下输入层最大长度200词嵌入层维度128Transformer编码器4个头全局池化全连接分类层7个输出inputs layers.Input(shape(200,)) x layers.Embedding(10000, 128)(inputs) x TransformerEncoder(128, 32, 4)(x) x layers.GlobalMaxPooling1D()(x) outputs layers.Dense(7, activationsoftmax)(x) model keras.Model(inputs, outputs)3. 模型训练与调优技巧3.1 训练配置我推荐这些超参数设置Batch Size: 128初始学习率: 3e-5Epochs: 10优化器: AdamW带权重衰减关键技巧是使用学习率warmup前10%的step线性增加学习率避免初期震荡。我在多个项目中发现这能提升最终准确率1-2个百分点。from transformers.optimization_tf import AdamWeightDecay optimizer AdamWeightDecay( learning_rate3e-5, weight_decay_rate0.01 ) model.compile(optimizeroptimizer, losssparse_categorical_crossentropy, metrics[accuracy])3.2 早停与模型保存为了防止过拟合我设置了两个回调EarlyStopping验证loss 3轮不下降就停止ModelCheckpoint只保存最佳模型callbacks [ keras.callbacks.EarlyStopping(patience3), keras.callbacks.ModelCheckpoint(best_model.h5, save_best_onlyTrue) ] history model.fit( train_ds, validation_dataval_ds, epochs10, callbackscallbacks )3.3 效果评估在测试集上这个模型达到了96.2%的准确率。混淆矩阵显示最容易混淆的是财经和时政类新闻这很合理因为它们经常有重叠词汇。我常用的评估指标组合准确率整体效果F1分数处理类别不平衡Cohens Kappa考虑随机猜测from sklearn.metrics import classification_report y_pred model.predict(test_ds) print(classification_report(y_true, y_pred.argmax(axis1)))4. 模型部署实战4.1 保存完整pipeline部署时不仅要保存模型还要保存tokenizer和标签编码器。我推荐用pickle保存这些组件import pickle # 保存模型 model.save(news_classifier.h5) # 保存tokenizer with open(tokenizer.pkl, wb) as f: pickle.dump(tokenizer, f) # 保存标签编码器 with open(label_encoder.pkl, wb) as f: pickle.dump(label_encoder, f)4.2 Flask API部署最简单的部署方式是Flask。下面是一个完整的API实现from flask import Flask, request, jsonify import tensorflow as tf import pickle app Flask(__name__) # 加载组件 model tf.keras.models.load_model(news_classifier.h5) with open(tokenizer.pkl, rb) as f: tokenizer pickle.load(f) with open(label_encoder.pkl, rb) as f: label_encoder pickle.load(f) app.route(/predict, methods[POST]) def predict(): text request.json[text] # 预处理 seq tokenizer.texts_to_sequences([text]) padded tf.keras.preprocessing.sequence.pad_sequences(seq, maxlen200) # 预测 pred model.predict(padded) # 返回结果 return jsonify({ class: label_encoder.inverse_transform([pred.argmax()])[0], prob: float(pred.max()) }) if __name__ __main__: app.run(host0.0.0.0, port5000)4.3 使用Hugging Face Hub如果想更专业的部署可以上传到Hugging Face Model Hubfrom huggingface_hub import push_to_hub_keras push_to_hub_keras( model, your-username/news-classifier, include_optimizerFalse )上传后就可以用一行代码加载model keras.models.load_from_hub(your-username/news-classifier)5. 实际应用中的经验分享在真实项目中我遇到过几个典型问题长文本处理新闻有时很长超过模型最大长度。我的解决方案是先分段然后对各段预测后投票。新词问题遇到元宇宙这种新词时tokenizer会拆分成未知标记。解决方法是用领域数据微调tokenizer。类别不平衡某些类别样本少。我采用过采样类别权重组合效果最好。领域迁移财经新闻模型用在科技新闻上效果下降。这时需要用少量目标领域数据微调。一个实用的技巧是建立反馈循环把线上预测不确定的样本预测概率0.7保存下来定期人工标注后加入训练集。这套方法让我的一个客户项目准确率从92%提升到了96.5%。最后提醒大家部署后一定要监控模型表现。我见过最惨的案例是某个新闻APP的分类模型因为新闻分布变化半年后准确率从95%跌到了60%都没人发现。建议设置准确率报警当周环比下降超过5%时触发警告。