这是大三上学期选修人工智能的一次实验。 该实验基于产生式系统实现了一个判断是否可以翘课的小型专家决策系统。
关于实验内容的设想来自于平时上课,有时候会出现一些情况导致学生犹豫是否要去上一节课。例如在遇到暴雨天气时、代课老师这节课的内容比较枯燥,没有交互时、或者这部分内容自己已经掌握之时,会有一部分同学选择在宿舍自习。以往出现这种情况就需要同学在自己内心做斗争,权衡利弊来形成决定。(对我这种选择困难症来说挺难受的- -!)而大部分情况下由于主观因素的影响,同学可能不能客观地做决策,这时一个可以代替人来做决策的专家系统就可以很好地避免此类问题。
对于决策的结果,只有两种答案:翘课,或不翘课。要针对不同情况产生不同的答案,就需要对每种情况有一个统一的度量标准。因此在该实验中设置了一个翘课系数来表示各个情况对最终决策的影响,也可以表示为在某情况下翘课(或不翘课)的意愿值。将其取值范围设为[-1,1],越接近1表示翘课意愿越大,而越接近-1则表示不翘课的意愿更大。这样对于各个不同的情况就可以分别计算它们对最终决策的影响。
要做决策除了一个统一的标准,还需要一套规则。该实验提前在规则集中录入了20条规则对应一些常见的情况,有些情况可以得到一个该情况对应的翘课系数,有的情况可以推出其他情况。规则集可以随时改写以满足不同的需求或者不同人的不同偏好。最后将当前的情况录入事实集,并且今后也可以随时修改。
对于翘课系数。由于翘课毕竟是不好的行为,因此初始值设置为-1,即没有特殊原因不翘课,即使有,也是非不得已不翘课。为了简单起见,在规则集中翘课系数都是精确到小数点后1位的值,因此在最终的推理路径输出中也只精确到了后一位。如果以后添加了更加复杂的规则,可以设置更加精细的翘课系数(并且代码中的精确度也应该修改)。
最后,本实验实现了推理机和知识库的分离,可以应对完全不同的情况而不需要或只需要修改少量的代码。并且在不修改推理机程序的前提下,能够向知识库添加、删除、修改规则。本实验使用C++语言,关于人机交互界面则使用MFC实现。最终的决策则是根据所有事实情况各个的翘课系数加权加和得到的最终系数来决定,若其大于零,则认为可以翘课,否则不翘课。
- 匹配失败还是无结果?
首先是一次不成功的匹配是失败的还是无结果的?上课学到的方法是每次匹配后都把已经匹配过的规则从规则集中移出,当规则集为空时则退出匹配循环。
但这样的策略有一个问题,即无法确定一个事实和一个前件是否是同一层次的,例如有规则“若气温超过40度,则太热了”和规则“若太热了,则翘课系数为0.2”。如果使用上述退出循环的算法,那么在事实集中只有“气温超过40度”时,这两条规则都将被移除,最后将得不到0.2的翘课系数。
为了解决这个问题,我改为移除事实集。在每次匹配(无论成功与否)后都将该事实从事实集中移出,由于每次信息都得到充分利用,因此不会出现上面的错误情况。还是以刚才的例子举例,此时将从事实集中删除“气温超过40度”,但匹配成功后事实集会加入“太热了”,并且“太热了”还可以继续成功地与规则进行匹配。
- 何时退出匹配循环?
什么时候退出匹配的循环过程。由于不是分类或判断系统,无法通过检查是否达到最终目标来退出循环。一开始的策略是判断事实集是否为空,若为空则退出匹配。但如果前件是通过且的关系连接起来的不同条件,那么在循环遍历所有事实集后才可以直到是否匹配此条规则,但此时若没有匹配成功,就找不到哪些是该移出的事实。只得在移出时根据规则集的前件来移出事实集。这就引出了另一个问题:如果事实集中有的事实在规则集中并没有前件与之对应,那么会永远也移出不了,那么就永远退不出匹配循环。
为了解决这个问题,我在每次匹配之后都将此时的事实集与上一次匹配之后的事实集作比较,如果两次匹配的事实集没有变化,就说明经过一轮匹配对结果并没有影响,那么此时就可以退出循环了。
- MFC如何判断edit是否是不可写状态的问题
关于这个问题我记录在了博客里。