资讯动态

融合Bloom分类学与Rasch模型的预训练嵌入解决知识追踪冷启动问题

发布时间:2026/10/22 18:29:18 来源:尧图企业网站定制
1. 这个工作到底在解决什么难题做知识追踪方向的人应该都有过这种体验模型结构调了半天AUC还是卡在零点七几上不去了。打开日志一看新上线的那些题目几乎没有交互记录模型面对它们的时候基本等于瞎猜。这就是知识追踪领域绕不开的痛点——数据稀疏。特别是Cold Start场景一个知识点第一次出现在题库里、一套试卷第一次被学生做历史交互数据为零再强大的序列模型也巧妇难为无米之炊。这篇IJCAI2020的论文标题里的PEBG是Pre-trained Embeddings Based on Blooms Taxonomy的缩写。作者团队想解决的问题非常明确能不能在下游知识追踪模型看到交互记录之前先让模型“认识”这道题本身换句话说与其等着交互数据来教模型不如提前用习题的文本描述、认知难度等元信息给每道题预训练一份“身份档案”再把这档案注入知识追踪模型。实验效果也确实能打在好几个公开数据集上DKVMN、DKT这类经典模型只要套上PEBGCold Start场景下的AUC都能明显涨一截。这篇解读适合谁如果你是做教育数据挖掘、智能学习系统、知识追踪方向的研究生或工程师这篇值得细看如果你手头正好有题库数据、想解决模型冷启动问题但不知道怎么下手这篇更是可以直接给你一条可落地的技术路线。整篇解读我会从问题动机、方法设计、模型融合、实验细节、复现避坑几个角度展开尽量讲清楚“为什么这么做”而不只是“做了什么”。2. 论文章法PEBG的三层设计2.1 Bloom分类学给习题贴认知标签要理解PEBG得先理解一个看起来和教育技术没多大关系的理论框架——Bloom分类学。1956年提出后来经过修订把认知目标分成记忆、理解、应用、分析、评价、创造六个层级。新版还有个重要改动每一层都配了对应的“行为动词”比如“记忆”对应列出、复述“理解”对应解释、分类“应用”对应执行、实施。论文的思路很直接把每道习题的题干文本拿去和这些行为动词做匹配判断这道题最接近哪个认知层级然后把这个层级编码成一个向量当作习题嵌入的一部分。为什么用Bloom分类学因为它是教育学界用得最广、最成熟的一套认知难度划分体系不是作者拍脑袋定的。做在线教育的题库如果做过教研标注大概率都能对上这套框架。这里有一个值得品味的细节Bloom分类学给习题提供的不是连续数值而是离散类别——六级分类里这道题属于第二级。这种离散信息本身包含了“这类题需要学生动用到哪一层认知能力”的语义恰恰是纯交互数据学不出来的。模型光知道“题目A答对了”和“题目B答错了”但不知道“题目A是记忆题题目B是分析题”这两者的区别对个性化学习路径推荐影响很大。我第一遍读论文时曾经疑惑为什么不做更细粒度的人工标注比如由教研专家给每道题打上“难度分值”或者“知识点向量”读下去才明白Bloom分类学最大的优势是“低成本可扩展”。你不需要资深教研员逐题精标用规则、用关键词匹配、用文本分类模型都能批量打标成本低、覆盖全、跨学科通用。而PEBG想要的就是大规模预训练成本可控是第一位的。2.2 Rasch模型给题目难度“统一度量”光有认知层级还不够。认知层级是类别标签但同一层级里的题难度也可能千差万别。比如同样是“应用”层级一道小学应用题和一道大学物理题难度完全不在一个量级。Bloom分类学这一层粒度太粗了PEBG需要更精细的连续度量于是作者引入了Rasch模型也就是项目反应理论里最基础的单参数逻辑斯蒂模型。Rasch模型的核心表达式不复杂P(答对) 1 / (1 exp(-(θ - b)))其中θ是学生能力参数b是题目难度参数。这道题越难b越大学生答对的概率越低。PEBG利用历史交互数据用Rasch模型估计每道题的难度参数b。这个b本身是一个标量但它非常有信息量——它把题目难度放在了和“学生能力”完全相同的度量尺度上。我尤其欣赏这一步的insight。很多做嵌入的人会想难度参数不就是一个数吗直接拼进特征向量里不就行了。但难点在于不同题库、不同版本、不同考试下的题目难度如果不经过模型校准原始数值根本不可比。比如A题库的题目平均正确率80%B题库的平均正确率50%你直接拿两边的正确率当难度特征拼进向量模型会发现特征分布都错位了。Rasch模型相当于一把“标准尺”通过最大似然估计把难度统一到同一个logit尺度上跨题库可比这样预训练的嵌入才有通用性。这一步本质上是在做“标准化”类似把不同省份的高考分数换算成标准分再比较逻辑是一样的。2.3 预训练嵌入怎么拼装Bloom标签和Rasch难度是PEBG的两个信息源但怎么把它们变成一个真正能用进下游模型的向量还要看第三个组件——基于参数的文本嵌入。简单说PEBG把每道题的题干、选项文字先通过一个预训练过的文本嵌入模型映射成基础向量然后把Bloom类别的编码向量和Rasch难度参数拼进这个向量里形成一个结构完整的预训练题目嵌入。这里值得展开说一下拼装策略。论文的常见做法是文本嵌入得到t维向量Bloom类别是6维one-hot或者通过嵌入矩阵映射成c维稠密向量Rasch难度是一个1维标量经过一个归一化或者小网络映射成d维向量最后三者向量拼接再过一个全连接层压缩成统一维度。这样一顿操作下来每个习题的预训练嵌入同时包含了三层信息语义层文本在说什么、认知层需要哪一层认知能力、统计层历史学生答对它的整体难度水平。这种“三合一”设计的巧妙之处在于信息互补性。文本语义解决“这道题在问什么”的问题Bloom标签解决“这道题需要什么层次的思维”的问题Rasch难度解决“这道题整体有多难”的问题。三个信号互相正交又都和“学生会不会做这道题”强相关。你说某道题文本是关于二次函数的Bloom层级是“应用”Rasch难度是1.2那模型不需要看任何学生交互也能对这道题有个基本判断——大概率中等偏难的应用题。有了这个判断模型在没有任何历史记录的情况下也能对该题做出比随机瞎猜明显靠谱的预测。注意这里所说的“拼接”和“过全连接层压缩”的细节不同复现实现在维度和融合方式上有差异但整体思想都是把三类信息融合成一个向量。首次接触时不用纠结具体维度大小先把信息流逻辑捋顺语义向量 认知标签向量 难度标量对齐拼接再映射到统一尺寸。3. 把PEBG塞进知识追踪模型一个完整的实操视角3.1 这支“预训练嵌入”要怎么注入讲完PEBG本身的构成下一个关键问题怎么把它用在知识追踪模型里论文里最典型的做法就是把它套在DKVMN这类记忆增强模型上。DKVMN可以说是知识追踪里的主力模型之一结构上由一个静态矩阵存储知识点、一个动态矩阵存储学生当前学习状态每次答题时根据相关性权重读取和写入记忆。它的核心流程是这样的拿到题目嵌入后先去和静态知识点做注意力看这道题和哪些知识点最相关然后从动态记忆里读出当前学生对这些知识点的掌握情况最后结合两者预测答对概率。PEBG融入DKVMN最直接的方式是替换模型的“题目嵌入”输入。原本DKVMN的题目嵌入是从交互序列里学出来的冷启动题目没有交互记录时嵌入就是随机初始化越学越懵。PEBG的做法是用预训练好的题目嵌入完成初始化后续训练时可以选择继续微调或冻结这样冷启动题目从一开始就有一个有意义的嵌入表示。具体来说代码层面的改动非常小。原本构建DKT或DKVMN输入时每个习题对应一个可学习的嵌入矩阵# 原始做法随机初始化一个习题嵌入表 question_embedding nn.Embedding(num_questions, embed_dim) input_vec question_embedding(question_ids)用了PEBG之后变成每次读题时拼接预训练信息# PEBG做法从外部知识源构建输入特征 # text_vec: 文本预训练向量, shape [batch, text_dim] # bloom_vec: Bloom类别向量, shape [batch, bloom_dim] # rasch_val: Rasch难度标量, shape [batch, 1] feature_vec torch.cat([text_vec, bloom_vec, rasch_val], dim-1) input_vec feature_projection(feature_vec) # 全连接层映射到模型输入维度就这么一步改动相当于让模型记住的不是一个随机数而是一道题的“身份档案”。交互记录仍然是由DKVMN负责建模的部分但模型从一开始就知道题目的语义和难度起点不一样了。后续在预测层加一个融合输出层把预训练嵌人和注意力读出来的知识掌握状态合并这就完成了整体改造。用几个数字对比一下效果假设你的题库里有一批新题没有任何交互记录。原始DKVMN在Cold Start下AUC可能在0.6到0.65之间徘徊基本是随机水平往上一点加入PEBG后在公开数据集上报告的Cold Start AUC提升从3%到6%不等数据稀疏程度越高收益越明显。也就是说交互数据越少PEBG这种纯题面特征发挥的作用越大。3.2 训练策略冻结还是微调这是个问题预训练嵌入进到下游模型后最经典的“灵魂拷问”是要不要让下游模型继续更新嵌入这也是论文实验部分验证得很细的一环。我读原论文时注意到作者团队在多个数据集上对比了不同微调策略。当时看到的一个明确结论是完全冻结预训练嵌入效果未必最好在数据量充足时让嵌入在下游任务上继续微调能够进一步适配当前数据分布。但数据很少时微调会让嵌入过拟合到少数几条交互上此时冻结反而更稳。我自己的复现体会是这个权衡有点像NLP里用BERT的方式——资源充足就full fine-tuning数据量小就freeze或者只调最后一两层。所以实操里可以做一个简单的动态策略前若干个epoch冻结嵌入让模型其他部分先收敛个七七八八然后解锁嵌入层用小学习率微调。这么做的好处是既能用预训练嵌入帮模型“热身”起来又不会被随机初始化的其他模块反向污染嵌入。模型训练里的具体配置也很关键。DKVMN类模型的隐藏维度通常取64到128这个量级PEBG预训练嵌入映射到同一个维度后注意力机制的维度匹配很顺畅。优化器选用Adam初始学习率从0.01开始跑几个epoch预热后衰减到0.001左右。这种配置在好几个公开教育数据集上都能稳定跑到不错的结果。提示如果你在复现时发现加了PEBG后效果反而没有提升先检查是不是把嵌入和原始随机嵌入一起拼进了模型导致特征维度膨胀、信息互相干扰。正确定位预训练嵌入的注入位置是替换而非追加。4. 论文实验背后的“隐藏剧情”数据处理里那些容易被忽略的细节4.1 数据划分与评估指标论文在实验里用到了几个公开的教育数据挖掘数据集这类数据都有一个共同特点严重不均衡。大多时候学生答对的比例在60%80%之间如果模型不做任何学习、全都预测“答对”准确率都已经不低了。所以论文强调用AUC作为核心评估指标这很有讲究。AUC对不均衡数据比较友好它能衡量模型对任意一对正负样本的排序能力也就是模型能不能把“答对”样例排得比“答错”样例更靠前。如果光看accuracy你很可能被“大部分学生都做对”的数据分布骗了。RMSE则用来度量预测概率和真实结果之间的误差这两个指标配合才能比较全面评估预测效果。比指标更需要注意的是数据划分方式。普通机器学习任务里随机划分训练集和测试集就行但知识追踪不行它有很强的时序依赖。答案预测必须保证测试集里的答题记录在学生完成之后否则就是“开卷考试”。如果你在复现时随手写了个train_test_split然后不管三七二十一分数据AUC可能会虚高不少但论文评审和真实业务里都会一眼看穿。正确做法是按时间截断前80%时间段的交互做训练后20%做测试再挑出测试集里的“新出现题目”作为Cold Start评估子集。4.2 从训练到收敛我踩过的性能缺口复现这类工作最简单的方式是开着默认参数直接训练。但真跑起来就会发现预训练嵌入虽然带来了冷启动增益同时也让训练变慢了一点。原因很简单嵌入向量维度变大了模型参数量涨了而且预训练特征常常带一些历史域偏移需要更多epoch来适应新分布。我第一次实现在某个公开数据集上复现时训练时间从大概半小时涨到了将近两个小时loss曲线前期还出现了轻微波动——就是嵌入微调在学习率设置不合理时产生的震荡。这时需要做两件事。第一把预训练嵌入相关部分的初始学习率调低一个数量级其他部分正常学习率第二训练过程中用early stopping盯验证集AUC避免嵌入后期过拟合。另一个影响性能的坑是题目文本预处理的质量。有的题库题干里有大量公式、图片标记直接丢进预训练模型会让嵌入向量被这些噪声污染。我在实操中会做一轮清洗把LaTeX公式统一转成[MATH]占位符图片标记全部去掉URL统一转成[URL]让文本嵌入学习的全是语义内容而不是格式噪声。5. 复现时最容易踩的坑与排查思路5.1 文本层面词典对齐与OOV问题PEBG预训练的基础是文本嵌入一定会遇到“词典之外”的OOV问题。很常见的情况是预训练阶段用的文本嵌入模型是在某个通用语料上训练的但真实题库里全是专业领域的术语、缩写、符号。比如教材里有很多带希腊字母的公式记号通用词向量模型根本不认识。如果文本向量直接用了整句的平均池化个别OOV词会被随机初始化或者被忽略整体嵌入质量就会下降。我的处理思路是把每道题的文本拆分成词后先过滤掉低频词和纯符号词再对剩余的词向量做加权平均——用词频做权重体现不同词的重要性。这一步做完虽然还有个别词没有完备的嵌入但整体向量不至于被噪声词带偏。如果你用的题库本身积累了比较多的文本也可以直接在题库语料上用word2vec、FastText这类轻量模型再训练一轮让嵌入空间更贴合这个领域的用词习惯。这样比直接套用通用预训练模型要靠谱得多。5.2 难度参数Rasch估计的两个坑Rasch模型看着简单但实际跑起来有两个大坑。第一是能力参数和难度参数的同时估计存在非识别问题需要一个锚定约束——实践中通常把学生能力均值设为0然后在此基础上估计题目难度。如果不做锚定不同批次跑出来的难度值可能整体平移没法统一使用。第二是极端题目问题。如果一道题所有人都答对或所有人都答错最大似然估计会给它一个理论上无穷大的难度值落到实数值上就是很大的正数或负数。这种极端值一旦直接拼入嵌入会把特征尺度撑爆模型学起来压力很大。实操中我做了个简单的归并把Rasch估计出来的难度分数按百分位缩放到[-1, 1]区间同时对上下2%的极端值做截断。这样既保留了难度区分度又防止极端值影响训练稳定性。如果你发现加入PEBG后loss变成NaN优先检查这个位置的数值。5.3 模型层面嵌入维度和注意力导致的隐性Bug还有一个隐蔽但关键的点预训练嵌入的维度要和下游模型的注意力维度对齐。以DKVMN为例它的注意力机制要对“题目嵌入”和“静态知识点矩阵”做点积两者的维度必须严格一致。如果你把预训练嵌入拼接成256维但DKVMN的其余部分是128维模型定义时会报错或者你手动切了一半向量进去注意力权重就会跟着出偏差。解决方法是加一个可学习的线性映射层把任意维度的预训练向量统一压到模型规定的输入维度。这个映射层本身参数很少训练代价不高却能保证信息无损注入。排查这类问题有个非常实用的调试方法把预训练嵌入随机打乱后重新跑一遍实验。如果模型效果没有明显下降说明嵌入没有真正起作用问题大概率出在注入位置、向量维度或融合权重上反之如果效果骤降说明预训练嵌入确实在模型中发挥了作用再继续深挖微调策略即可。这个诊断思路花不了多少时间但能帮你快速定位大部分“加了等于没加”的反常情况。6. 从这篇论文里还能带走什么6.1 预训练思想在教育数据上的迁移价值PEBG这篇论文往小了说是一个嵌入预训练方法往大了说它给教育AI提供了一个很实用的方法论样例当交互数据稀疏时不要只盯着模型结构回头看看题目本身的元信息。这个思路可以迁移到很多方向。比如智能组卷、个性化推题、认知诊断几乎每个任务都面临冷启动。你手头如果有一批新题目没有答题记录但你知道它的教材版本、知识点标签、题型、难度预估值——这些信息完全可以用类似PEBG的方式先拼一个“题目嵌入”再交给下游任务模型。这个方法还很容易修正如果题目有明确的知识点图谱关系可以把图嵌入替换文本嵌入如果题库有老师标注的能力维度可以把Bloom标签替换成更细的标签体系如果某些学科有明确的公式结构甚至可以用结构编码器替换文本编码器。PEBG最核心的贡献不是它用了什么具体的编码器而是它示范了“如何把非序列的外部知识转化为下游序列模型能用的向量”这个套路放到今天依然不过时。6.2 如果我自己设计扩展实验我会怎么做读这篇论文时我脑海里一直萦绕着一个问题Rasch难度是全局难度但一道题对不同能力段的学生难度感知可能完全不同。如果只是把Rasch难度作为一个全局标量丢进嵌入等于把难度当作一个静态性质丢失了和学生能力交互的信息。后续如果要扩展我会考虑把习题嵌入和学生表征做一次交叉生成一个“题-生能力差异向量”再注入预测层。另外Bloom分类法的标注质量对结果影响也很大规则匹配会引入不少噪声有条件的话可以再训练一个文本分类器来打标并在标注置信度高的子集上验证嵌入质量这个方向也值得做一组对照实验。最后再说一点个人体会。每次复现这类论文我都提醒自己方法论的价值不在公式和图表里而在解决真实问题的过程中。PEBG的设计思路并不复杂但它抓住了一个对业务影响极大的场景——冷启动——并给出了一个低成本、可落地的解法。做技术的同学不妨多积累这类“小而锋利”的思路比一味堆模型结构要实用得多。如果你正被冷启动问题困扰可以先不急着换模型试着从手头数据的“题面信息”里找找机会也许PEBG就是一个不错的起点。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑