BKT训练及测试-大规模拟合隐马尔科夫模型工具
此命令行工具由C/C++编写,目的是为了在大型数据集中拟合隐马尔可夫模型(HMM)。它针对一种用于教育领域的特殊HMM,称为**贝叶斯知识追踪(BKT)**模型。
贝叶斯知识追踪
贝叶斯知识训练(Bayesian Knowledge Training,BKT)是一种在智能辅导系统(ITS)领域广泛使用的用户建模方法。在ITS中,通常会使用知识点标记学生正在解答得问题。我们认为学生解答问题的过程是练习了一个或多个技能的过程。学生模型(BKT是其中之一)判断解决问题过程中一系列正确或不正确的结果,以确定该技能是否被掌握。BKT使用隐马尔可夫模型计算学生技能掌握的概率,其中有两种类型的节点:状态节点表示技能掌握情况,它们的值为掌握或未掌握,以及观察节点,它们的值为正确或不正确。
标准BKT中,每一个知识点都有如下的参数:
- p-init/
P(Lo)
:知识点先验已掌握的概率; - p-learn/
P(T)
:经过学习之后,某一知识点由不会到会的学习转移概率; - p-forget/
P(F)
:学习过程中,某一知识点由会到不会的遗忘概率;通常情况下p(F)
被设为0
,不计入参数中; - p-slip/
P(S)
:在知道某一知识点时,做题表现为错误的失误概率; - p-guess/
P(G)
:在不知道某一知识点时,做题表现为正确的猜测概率。
BKT参数可以用向量或矩阵形式表示。全局先验的向量P(Lo)
参数。在先验向量中有N=2
个元素,假设P(Lo)
是
在状态转移矩阵A
中,p(T)
是一个元素,涵盖掌握状态变化的概率,其大小为N * N
。设置A [1,2]=0
将不予捕获遗忘过程(从掌握到未掌握)。P(T)
对应于A [2,1]
- 从未掌握到掌握。
观测矩阵B
中指定了P(G)
和P(S)
,该矩阵的大小为N*M
,其中M
是观察数(在标准BKT中为M=2)。第一列对应于正确的观察结果,第二列对应于错误的观察结果。在具有两个观察结果的标准BKT中,P(G)
是B[2,1] - 未掌握的技能但是正确的响应,P(S)
是B[1,2] - 掌握的技能但是错误的响应。
获取并编译代码
标准BKT代码的公开版本可以通过GitHub仓库获得。如果你安装了git工具,使用下面的命令来获取源代码。
1 | git clone https://github.com/myudelson/hmm-scalable |
使用make all
指令编译。如果在Linux上,g++/gcc编译器和Open MP库应该已经安装了。在Mac OX上,你需要通过xcode-select --install
命令来安装Xcode命令行工具。g++/gcc
编译器与Open MP(默认情况下不再与Mac OS X捆绑)可以从这里下载。如果你是在Windows上,你可能需要安装cygwin
,并有g++/gcc
编译器可用,并确保也安装make
工具。
数据
输入文件
输入的数据文件应该是一个具有Unix行末编码的文本文件。其格式为四个以Tab
分隔的列:观测、学生、问题/问题步骤、知识点
。观测值是一个以1开头的整数。对于双状态的BKT,建议使用1表示正确,2表示不正确。学生、问题或一个问题步骤、以及知识点都是一个字符串标签。多知识点标签应该由你选择的字符来分隔(不要使用Tab)。下面是一个有几行输入的例子。在这里~
被用作分隔符。
1 | -- input file -- |
如果某一行的数据没有知识点标签,则使用.
符号。在测试数据中,该工具将使用已知的观测值进行训练,并对缺失的观测值进行预测,这些观测值应该有.
而不是观测的数值(1、2或其他)。
输出文件
输出文件是模型文件和预测文件。
模型文件
模型文件包含关于数据的一般信息,例如观测数、知识点数和问题/问题步骤的数量,也包括模型的参数。
1 | -- model file -- |
例子包括
-
具体的求解器算法(
1.1
) -
一个知识点(
nK=1
) -
一个学生(
nG=1
) -
两个隐藏状态(
nS=2
) -
两个观测值(
nO=2
) -
知识点的编号从
0
开始 -
知识点名称为
multiplication-skill
-
PI
对应初始化概率向量;PI
的第一个元素p(Lo)=0.45
-
A
对应状态转移矩阵;A
的第三个元素p(T)=0.4
-
B
对应confusion矩阵,表示可观察变量与隐藏变量的转换概率;B
的第二和第三个元素分别是p(S)=0.21
和p(G)=0.22
。
预测文件
预测文件由对输入文件的每一行的模型预测组成。根据选项的不同(见下面的参数说明),输出学生回答的概率分布(正确和不正确的概率)。此外还可以输出针对特定知识节点隐藏状态值的概率分布。概率值以Tab
分隔。请看下面的输出文件的例子。
1 | -- prediction file -- |
上述例子是一个有nO=2个观测值的标准BKT模型,它将包含两列,中间用Tab
分隔开。
- 第一列是BKT模型估计学生在此次观察中回答正确的先验概率。
- 第二列是对正确概率的补充,也就是答错的概率。
训练BKT模型
trainhmm
使用以下的参数:
trainhmm [选项] 输入文件 [[模型文件] 预测文件]
选项:
-s
:格式-s 结构.求解器[求解器设置]
- 结构:
- 1- 知识点
- 2- 用户
- 求解器:
- 1-Baum-Welch算法
- 2-梯度下降法
- 3-共轭梯度法
- 1-Polak-Ribière-Polyak
- 2-Fletcher–Reeves
- 3-Hestenes-Stiefel
- 4-Dai-Yuan
例如:-s 1.3.1
指按知识点结构,求解器使用共轭梯度下降,求解器设置为Polak-Ribière-Polyak
-s 2.1
指按学生结构,求解器使用Baum-Welch。
-S
:对前向/后向变量进行缩放:0-关闭(默认),1-打开。只在Baum-Welch求解器中生效-s 1.1
,否则自动设置为关闭。
-e
:设置允许的终止判据(默认0.001);可以被计算为对数似然中每个数据点的变化,例如-e 0.00001,l
。
-i
:最大迭代数(默认200)
-q
:无输出的安静模式,0-否(默认),1-是
-n
:隐藏状态的个数,应大于等于2(默认2)
-0
:逗号分隔的初始参数,用于初始概率、状态转移概率和混淆概率,跳过每个向量(矩阵行)的最后一个值,因为它们的总和应该是1;默认是0.5,1.0,0.4,0.8,0.2。
-l
:参数的下限,以逗号分隔的初始概率、状态转移概率和混淆概率(无跳转);默认为0,0,1,0,0,0,0,0。
-u
:参数的上限,用逗号分隔的初始概率、状态转移概率和混淆概率(无跳转);默认为1,1,1,1,1,1,0.3,0.3,1,滑动和猜测的上限为0.3。
-c
:用于 L2 惩罚的 C 权重和中心点的规格,空(默认)。对于标准BKT - 4个逗号分隔的数字: 惩罚的C权重和中心点,分别用于PI、A和B矩阵。如果用于有学生效应的iBKT,将使用8个值,其中4个附加值用于学生矩阵。例如,-c 1.0,0.5,0.5,0.0。
-f
:拟合为一个知识点,0-否(默认),1-拟合为一个知识点并使用参数作为多知识点的起点,2-强制使用一个知识点。
-m
:输出模型拟合指标(AIC、BIC、RMSE) 0-否(默认),1-是。要指定要报告指标的观测值,请在,后面列出。例如,-m 0
, -m 1
(默认情况下,假设观测值为1), -m 1,2
(计算观测值2的度量)。与-v
选项不兼容。
-v
:交叉验证折数、分层采样法、验证目标状态、折数输入/输出文件,默认0(无交叉验证),如-v 5,i,2
,5折,项目分层的c.-v.,预测状态2, -v 10
- 10折,主题分层的c.-v. v.默认预测状态1,或者 -v 10,g,1
, -v 5,n,2,folds.txt,o
- 5折非分层c.-v.预测状态2,[o]输出折叠到folds.txt
,这里 -v 5,n,2,folds.txt,i
,折叠实际上是从文件中读取[i]n。
-p
:输出模型对训练集的预测,0-否(默认),1-是;2-是,加上输出状态概率;与-v
和-m
参数一起工作。
-U
:控制状态的概率分布如何被更新。采取以下格式-U r|g[,t|g]
,其中
- 第一个字符-控制预测如何处理已知观测值
- 第二个字符-预测如何处理未知观测值
- 第三个字符-是否输出先验概率。
处理已知观测值r
–揭示实际观测值以更新状态概率分布(对模拟实际系统如何工作有意义),g
–根据预测结果猜测观测值(arg max)–在比较模型时更合适(这样就不会有关于观测的信息被揭示)。处理未知的观测值(标记为.-点):t
-仅使用过渡矩阵,g
-猜测观测值。默认(如果省略)是-U r,t
。例如,-U g,g
需要使用模型参数和状态分布概率的运行值来猜测观察结果是什么。
-d
:分隔符,用于每次观察中的多种知识点;每次观察单一知识点(默认),否则 - 分隔符,例如 -d ~
。
-b
:将输入文件转换为由inputconvert
工具从文本文件创建的二进制输入文件。
-B
:分别阻止对先验、过渡或排放参数的重新估计(默认为-B 0,0,0
),要阻止对过渡概率的重新估计,请指定-B 0,1,0
。???
-P
:使用并行处理,
- 默认 - 0(无并行处理)
- 1 - 分别拟合单独的知识点/学生
- 2 - 分别拟合知识点/学生中的单独序列。
-o
:除了打印到控制台外,还可以打印输出到该选项中指定的文件(默认为空,不做额外的打印)。
使用模型预测
predicthmm
使用以下格式:
predicthmm [选项] 输入文件 模型文件 [预测文件]
-q
:没有输出的安静模式,0-否(默认),1-是。
-m
:输出模型拟合质量评判(赤池信息量(AIC),贝叶斯信息量(BIC),均方根误差(RMSE)),0-否(默认),1-是。要指定要报告哪些指标的观察,请在,
之后列出。例如-m 0
,-m 1
(默认使用观察1
),-m 1,2
(为观察2
计算度量指标)。不能与-v
同时运行。
-d
:每个观察中多种知识点使用分隔符号;每个观察一个知识点(默认),否则使用分隔符,如-d~
。
-b
:将输入文件视为由inputconvert
工具从文本文件创建的二进制文件。
-p
:输出模型对训练集的预测,0-否(默认),1-是;2-是,并且加上输出状态概率;与-v
和-m
参数一起工作
-U
:控制状态的概率分布如何被更新。采用-U r|[g,t|g]
其中
- 第一个字符–控制如何预测已知的观测值
- 第二个字符–预测如何处理未知的观测值
- 第三个字符–是否输出先验概率
处理已知观测值r
–揭示实际观测值以更新状态概率分布(对模拟实际系统如何工作有意义),g
–根据预测结果猜测观测值(arg max)–在比较模型时更合适(这样就不会有关于观测的信息被揭示)。处理未知的观测值(标记为.-点):t
-仅使用过渡矩阵,g
-猜测观测值。默认(如果省略)是-U r,t
。例如,-U g,g
需要使用模型参数和状态分布概率的运行值来猜测观察结果是什么。
例子
小样本数据文件toy_data.txt
使用一下BKT参数生成的:pLo=0.4, pT=0.35, pS=0.25, pG=0.12.
为了使用EM算法拟合这些数据的BKT模型,运行以下命令:
1 | ./trainhmm -s 1.1 -m 1 -p 1 toy_data.txt model.txt predict.txt |
该模型将有90%的准确性,均方根误差(RMSE)= 0.302691,恢复的BKT参数将是:
pLo=0.00000000,pT=0.16676161,pS=0.00044059,pG=0.00038573
。整体的对数似然,在三次迭代中从9.3763477
上升到10.4379501
。
如果使用-s 1.2
参数的梯度下降法来拟合BKT模型,恢复的参数将是
pLo=0.00000000,pT=0.3095828498,pS=0.18955371,pG=0.16195590
,准确率仍保持在90%,同时RMSE
=0.344145
。经过19次迭代后,对数似然从9.3763477
变为8.0992564
。
运行以下命令生成用先前模型拟合的预测结果:
1 | ./predicthmm -p 1 toy_data_test.txt model.txt predict.txt |
可以使用KDD Cup 2010数据集
进行测试,此数据集可以从这里下载,它由训练集和挑战集组成。为了测试该工具,请下载挑战代数集,它有超过3300名学生的大约900万个事务。训练文件应该被修剪成工具的格式。请看下面的shell命令,可以做到这一点。
1 | gawk -F"\t" 'BEGIN{OFS="\t"} {if(NR==1)next; skill=$20; gsub("~~", "~", skill); if(skill=="") skill="."; else { skill=$3"__"skill; gsub(/~/, "~"$3"__",skill);} print 2-$14,$2,$3"__"$4,skill;}' algebra_2008_2009_train.txt > a89_kts_train.txt |
为了此数据集能够使用梯度下降法拟合此BKT模型,同时计算拟合指标和预测值,请运行以下命令:
1 | ./trainhmm -s 1.2 -d ~ -m 1 -p 1 a89_kts_train.txt model.txt predict.txt |
根据你的硬件设备情况,模型大约1-2分钟内拟合成功。