Spacy 3.0无配置文件实现早停、交叉验证与权重初始化设随机种子
Spacy文本分类:无配置文件实现早停、交叉验证与随机种子固定
1. 固定随机种子
在训练开始前,通过以下代码固定全局随机种子,确保权重初始化和训练过程的可复现性:
import spacy import random import numpy as np import os # 固定随机种子 SEED = 42 os.environ['PYTHONHASHSEED'] = str(SEED) random.seed(SEED) np.random.seed(SEED) spacy.util.fix_random_seed(SEED)
2. 手动实现早停
在训练循环中跟踪验证集性能,设置patience参数(允许连续多少个epoch无性能提升),当触发条件时终止训练:
- 记录最佳验证得分
- 统计连续无提升的epoch数
- 当计数超过
patience时停止训练 - 可选:保存性能最佳的模型
3. K折交叉验证
使用KFold拆分数据集,每次用K-1份数据训练,1份验证,循环完成所有折后计算平均性能。这里可以借助sklearn.model_selection.KFold实现数据拆分。
完整整合代码
import spacy import random import numpy as np import os from sklearn.model_selection import KFold from spacy.training import Example # ---------------------- # 1. 固定随机种子 # ---------------------- SEED = 42 os.environ['PYTHONHASHSEED'] = str(SEED) random.seed(SEED) np.random.seed(SEED) spacy.util.fix_random_seed(SEED) # 准备数据集(格式示例:[(文本, {"cats": {"类别1": 0, "类别2": 1}}), ...]) all_data = [...] # 替换为你的完整数据集 # ---------------------- # 2. K折交叉验证设置 # ---------------------- K = 5 # 5折交叉验证 kf = KFold(n_splits=K, shuffle=True, random_state=SEED) fold_scores = [] for fold_idx, (train_idx, val_idx) in enumerate(kf.split(all_data)): print(f"\n=== 第 {fold_idx+1}/{K} 折 ===") # 拆分训练和验证数据 train_data = [all_data[i] for i in train_idx] val_data = [all_data[i] for i in val_idx] # 初始化Spacy文本分类模型 nlp = spacy.blank("en") textcat = nlp.add_pipe("textcat", config={"exclusive_classes": True, "architecture": "simple_cnn"}) # 添加标签 labels = list(set([list(item[1]["cats"].keys())[0] for item in all_data])) for label in labels: textcat.add_label(label) # 初始化优化器 optimizer = nlp.begin_training() # ---------------------- # 3. 早停设置 # ---------------------- PATIENCE = 3 # 连续3个epoch无提升则停止 best_val_score = 0.0 no_improve_count = 0 max_epochs = 25 for epoch in range(max_epochs): losses = {} # 打乱训练数据 random.shuffle(train_data) # 小批量训练 batches = spacy.util.minibatch(train_data, size=8) for batch in batches: examples = [] for text, annotations in batch: doc = nlp.make_doc(text) example = Example.from_dict(doc, annotations) examples.append(example) nlp.update(examples, sgd=optimizer, losses=losses) print(f"Epoch {epoch+1}, 训练损失: {losses['textcat']:.4f}") # 验证阶段 val_score = nlp.evaluate(val_data)["textcat_f"] # 取F1得分作为早停指标 print(f"验证F1得分: {val_score:.4f}") # 早停逻辑 if val_score > best_val_score: best_val_score = val_score no_improve_count = 0 # 保存最佳模型 nlp.to_disk(f"./best_model_fold_{fold_idx+1}") else: no_improve_count += 1 if no_improve_count >= PATIENCE: print(f"连续{PATIENCE}个epoch无性能提升,提前停止训练") break fold_scores.append(best_val_score) print(f"第{fold_idx+1}折最佳F1得分: {best_val_score:.4f}") # 输出交叉验证平均得分 print(f"\n=== 交叉验证结果 ===") print(f"各折最佳F1得分: {[round(s,4) for s in fold_scores]}") print(f"平均F1得分: {np.mean(fold_scores):.4f} ± {np.std(fold_scores):.4f}")
关键说明
- 随机种子:通过全局设置确保模型初始化、数据拆分、训练过程的随机性完全可控,避免每次训练结果差异过大。
- 早停:以验证集F1得分为指标,当连续指定次数epoch无提升时终止训练,避免过拟合,同时保存性能最优的模型。
- 交叉验证:通过KFold将数据集拆分为K份,每份轮流作为验证集,最终取平均性能作为模型的可靠评估结果。
内容的提问来源于stack exchange,提问作者Pranjal Sharma
相关产品推荐
相关产品推荐

