从 SM-2 到 FSRS:Anki 背后的间隔重复算法三十年
从 SM-2 到 FSRSAnki 背后的间隔重复算法三十年【免费下载链接】ankiAnki is a smart spaced repetition flashcard program项目地址: https://gitcode.com/GitHub_Trending/an/anki记忆会随时间衰减这是艾宾浩斯在 1885 年用无意义音节实验就揭示的规律但在什么时候复习最划算人类摸索了整整一个世纪。1980 年代末波兰研究者 Piotr Woźniak 在 SuperMemo 项目中提出了 SM-2 算法把间隔重复从经验直觉变成可计算的调度规则三十多年后这一算法仍是 Anki 的默认调度内核。而 2023 年发布的 Anki 23.10正式把另一个来自开源社区的新算法 FSRS 收入了内核让复习间隔第一次可以由每个用户的历史数据动态拟合。本文结合 Anki 仓库的调度器源码与官方文档拆解这条从 SM-2 到 FSRS 的演进主线算法换了什么、没换什么以及它对每天点开 Anki 复习的普通用户究竟意味着什么。一、SuperMemo 到 SM-2间隔重复的起点间隔重复的核心矛盾很简单复习太密浪费时间复习太疏则遗忘。SM-2 的贡献在于用两个变量把下一间隔变成了可迭代计算的公式——间隔interval和难度因子ease factor, EF。SM-2 的基本规则是每张卡毕业时获得初始 EF默认 2.5每次复习后根据按键质量调整 EF下一次间隔 当前间隔 × EF。这套规则被无数后来者沿用Anki 也不例外。在仓库的调度器源码 rslib/src/scheduler/states/review.rs 中SM-2 的骨架仍然清晰可辨pub const INITIAL_EASE_FACTOR: f32 2.5; pub const MINIMUM_EASE_FACTOR: f32 1.3; pub const EASE_FACTOR_AGAIN_DELTA: f32 -0.2; pub const EASE_FACTOR_HARD_DELTA: f32 -0.15; pub const EASE_FACTOR_EASY_DELTA: f32 0.15;这里每个常量都对应 SM-2 的一条规则初始难度 2.5忘记扣 0.2困难扣 0.15简单加 0.15难度因子永不低于 1.3——SuperMemo 的研究发现EF 低于 130% 的卡会频繁到期只会徒增烦扰。但 Anki 从第一天起就不是 SM-2 的忠实复刻官方 FAQ 在 docs-site/faqs/what-spaced-repetition-algorithm.mdx 中明确列出了若干改良点SM-2 规定新卡首两次间隔为 1 天、6 天Anki 则把初始学习步骤完全交给用户配置并承认学习阶段的失败不应影响日后复习难度——反复失败是习得过程的常态不该因此被惩罚复习按钮从 6 键压缩为 4 键失败只有一个档位因为失败复习占比很小用通过档位微调难度因子已足够逾期未复习的卡在下次作答时会获得间隔补偿迟交但还记得的卡不会被一刀切简单档不仅提高 EF还会在本次间隔上追加额外加成学习中的连续失败不会进一步拉低难度因子从而避免 SM-2 著名的低间隔地狱low interval hell——即一张卡因反复答错被卡在极短间隔里出不来。这些改动在 rslib/src/scheduler/states/review.rs 的passing_nonearly_review_intervals等函数中都有对应的实现逻辑hard/good/easy 三档间隔分别由hard_multiplier、难度因子与easy_multiplier复合计算逾期天数days_late还会以折半甚至全额的方式计入下一间隔。这套经验参数 固定规则的设计正是 SM-2 时代的典型特征算法作者通过大量人工实验确定常数再用一套乘法规则服务所有用户。它的优点是可解释、零数据成本、开箱即用代价则是——它假设所有人都拥有同一条遗忘曲线。二、FSRS 的突破从经验参数到数据驱动FSRSFree Spaced Repetition Scheduler的野心是把所有人的遗忘曲线都一样这个假设彻底推翻。它建立在记忆三成分模型Three Component Model of Memory之上。官方文档 docs-site/faqs/what-spaced-repetition-algorithm.mdx 给出了三个核心变量的定义可提取性 RRetrievability某一时刻成功回忆的概率由距上次复习的时间与记忆稳定性决定稳定性 SStabilityR 从 100% 降到 90% 所需的天数S 365 意味着一年后回忆概率才会跌破九成难度 DDifficulty材料本身的固有复杂度反映复习后提升稳定性的难易程度。三者合称记忆状态memory state。R 随时间每日衰减而 D 与 S 只在复习发生时被更新——这意味着每张卡都拥有独立的内存状态曲线而不是像 SM-2 那样只有一张全局共享的 EF 因子表。差异的关键在参数来源。SM-2 的常数来自作者的经验实验FSRS 则把调度问题交给机器学习Anki 的 rslib/src/scheduler/fsrs/params.rs 里compute_params函数读取用户的复习日志revlog将其转换为带时间间隔delta_t的 FSRS 训练样本然后用梯度优化拟合出一组专属于该用户的参数let input ComputeParametersInput { train_set: items.clone(), card_ids: Some(card_ids), progress: Some(progress.clone()), enable_short_term: true, num_relearning_steps: Some(num_of_relearning_steps), training_config: Some(TrainingConfig { num_epochs: 8, ..Default::default() }), }; let mut params fsrs::compute_parameters(input.clone())?;这段代码还透露了两个值得注意的工程细节其一优化有最低数据门槛。界面文案在 ftl/core/deck-config.ftl 中写得直白——You must have at least 400 reviews for this operation不足 400 条复习记录时无法执行参数优化因为机器学习需要足够样本才能拟合出有意义的曲线。训练完成后代码还会用 log-loss 比较优化后参数与当前参数的预测误差若优化结果没有显著改善current_log_loss optimized_log_loss则保守地保留原参数避免劣化已有调度。其二优化结果是启发式 兜底的双保险。参数拟合并非无限自由度get_decay_from_params会根据参数长度区分 FSRS-5 与 FSRS-6 的衰减常量FSRS5_DEFAULT_DECAY/FSRS6_DEFAULT_DECAY整套训练默认只跑 8 个 epoch并且没有强行要求模型在训练集上过拟合到最好——目标是找到能泛化到未来复习的规律而不是记住过去。更值得注意的是记忆状态在存储层面的落地。在 rslib/src/card/mod.rs 中每张卡都新增了三个字段pub(crate) memory_state: OptionFsrsMemoryState, pub(crate) desired_retention: Optionf32, pub(crate) decay: Optionf32,其中FsrsMemoryState只包含两个数值——stability以天为单位的记忆稳定性和difficulty1.0–10.0 的难度分。这套设计让 Anki 得以在批量重排reschedule时把每张卡的真实记忆状态写入 SQLite 数据库rslib/src/scheduler/fsrs/memory_state.rs 中memory_state_batch以 1000 张卡为一批调用 fsrs 库批量计算状态并让卡片、统计页、浏览器搜索都能直接读取而无需每次回到牌组配置里翻参数。从经验常数到数据驱动FSRS 还顺手解决了一个 SM-2 长期处理不好的场景延迟复习。用户中断几周或几个月后回来SM-2 只能靠简单的迟到加成估算而 FSRS 直接用真实经过的天数delta_t更新 R 值再据此刻画下一状态官方文档明确声称FSRS is also much better at scheduling cards that have been reviewed with a delay。三、对普通用户意味着什么算法之争如果只停留在论文层面普通用户并不会关心。FSRS 真正改变日常体验的是它在 Anki 界面里把调参这件事简化为一个旋钮。在 docs-site/manual/deck-options.mdx 的 FSRS 章节中官方给出了极其直白的指引开启 FSRS 后SM-2 时代的毕业间隔Graduating intervalEasy bonus等选项全部隐藏取而代之的是一个Desired retention期望保留率滑块。它的含义是当你复习一张到期的卡时希望它被记住的概率是多少。默认值 90%高于 97% 则工作量会迅速失控。这就是 FSRS 对普通用户最重要的意义用目标代替规则。在 SM-2 下用户想调节工作量需要理解 EF、间隔修正、最大间隔等一整套概念在 FSRS 下你只需要回答我想记住多少——剩下的由模型反推。想要更轻松把保留率调到 85%想要更牢固调到 95%仅此而已。配合这一旋钮的还有两个面向决策而非调参的功能一键优化点一下 Optimize 按钮Anki 读取你的全部复习历史用机器学习拟合出属于你个人的参数官方建议每月执行一次即可——数据越多拟合越准。计算最低推荐保留率CMRR与模拟器rslib/src/scheduler/fsrs/retention.rs 中的compute_optimal_retention会基于你的真实卡片状态难度、稳定性、可提取性模拟未来数十天的复习负荷找出学得最多、耗时最少的保留率拐点答案被约束在 0.7–0.95 之间。用户在设置界面就能看到如果保留率设为 X你每天要复习 Y 张卡的个人化曲线而不是听信任何网上的经验值。对迁移者来说从 SM-2 切到 FSRS 也基本是平滑的。历史复习日志revlog是 FSRS 的训练素材Anki 在 rslib/src/scheduler/fsrs/memory_state.rs 中提供了完整的回填机制当卡片缺少完整复习历史时会先用 SM-2 的难度因子和间隔推断一个初始记忆状态memory_state_from_sm2再让 FSRS 接管后续调度——这意味着老用户的历史数据不会作废而是被翻译成新模型的起点。配合Reschedule cards on change选项甚至可以把已有的到期时间整体重排到 FSRS 认为更合理的位置。最后还有两个容易被忽视的行为约束它们比任何算法细节都更影响实际效果。文档在 FSRS 章节中反复强调忘记时必须按 Again而不是 Hard——FSRS 把 Hard 视为回忆成功但吃力若用它掩盖遗忘所有间隔都会被不合理地拉长以及涉及间隔调度的第三方插件不应与 FSRS 混用因为任何外部的间隔改写都会污染模型的输入数据。而仓库中的负载均衡器rslib/src/scheduler/states/load_balancer.rs则在模型给出理想间隔后通过加权随机把到期日摊到 90 天窗口内避免复习量在某几天扎堆——算法负责记得牢它负责不累死。结语回看这三十年SM-2 的价值不在于公式本身而在于它把何时复习从玄学变成了可计算、可迭代的工程问题FSRS 的突破则在于承认了一个朴素事实——遗忘曲线从来不是一条而是每人一条、每卡一条。Anki 在这条主线上始终扮演着算法民主化的角色因为 SuperMemo 的最新算法是闭源且需要授权的这个开源项目只能拥抱同样开源的方案——官方 FAQ 直言初步测试表明 FSRS 大致与 SM-17 相当。于是我们得以看到一个罕见的样本一款用户量巨大的记忆软件把调度权从作者经验移交给了用户自己的数据并且只留一个旋钮让每个人在记得牢与复习少之间做出诚实的取舍。【免费下载链接】ankiAnki is a smart spaced repetition flashcard program项目地址: https://gitcode.com/GitHub_Trending/an/anki创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

JavaScript大整数精度丢失与BigInt:从雪花ID实战出发

JavaScript大整数精度丢失与BigInt:从雪花ID实战出发

1. 一个 19 位雪花 ID,怎么到浏览器就变了样1.1 那天早上我遇到的"幽灵订单号"事情是这样的:周一刚坐下,客服就转来一个工单,说某个订单在后台管理系统里显示成了另一个订单号,用户对不上账。我查了半天数据…

2026/10/10 22:02:51 阅读更多 →
Python-OpenCV车牌识别系统实战:从定位、分割到字符识别

Python-OpenCV车牌识别系统实战:从定位、分割到字符识别

简介:这是一份基于Python与OpenCV实现的车牌识别系统完整项目,面向人工智能、计算机视觉方向的开发者和学生。项目在传统图片车牌识别基础上,新增OpenCV摄像头实时识别功能,并优化识别模块函数逻辑,显著提升识别效率与…

2026/10/10 22:02:51 阅读更多 →
潜艇卫星图目标检测数据集实战:从零训练YOLOv8与旋转框检测器

潜艇卫星图目标检测数据集实战:从零训练YOLOv8与旋转框检测器

简介:这份资源是面向人工智能与计算机视觉方向研究者、学生及算法工程师的潜艇卫星图目标检测数据集,可用于训练和验证水下目标识别模型,服务于海洋监控、国防安全与环境监测等场景。压缩包共2001个文件,包含1000张10241024像素的…

2026/10/10 22:02:51 阅读更多 →

最新新闻

Java日期时间转换实战:Date/Long/时间戳与格式化全解析

Java日期时间转换实战:Date/Long/时间戳与格式化全解析

2. 为什么要写这篇指南先说个真实场景。上周有个同事调接口,前端传了个时间戳过来,他拿new Date(Long.parseLong(str))一解析,页面上的日期直接变成了 1970 年。排查了半天,发现是前端把毫秒当秒传了,后端拿到手就当成…

2026/10/10 23:24:59 阅读更多 →
PyCharm调试asyncio报错ProactorEventLoop缺少_compute_internal_coro的解决方案

PyCharm调试asyncio报错ProactorEventLoop缺少_compute_internal_coro的解决方案

1. 这是哪来的报错:从现象到定性1.1 报错现场你在 Windows 上用 PyCharm 打开一个用 asyncio 写的项目,代码里设了个断点,点下 Debug 按钮。程序刚跑到断点那一行,你可能还没看到绿色的当前行标记,控制台先给你甩出一行…

2026/10/10 23:24:59 阅读更多 →
微调GPT-2写诗对战:中文诗词数据+keras_nlp全流程,还能救活你的对联项目

微调GPT-2写诗对战:中文诗词数据+keras_nlp全流程,还能救活你的对联项目

微调GPT-2写诗对战:中文诗词数据keras_nlp全流程,还能救活你的对联项目 【免费下载链接】gpt2 项目地址: https://ai.gitcode.com/hf_mirrors/openai-community/gpt2 GPT-2 诞生七年,参数规模已被后辈甩开两个数量级,但它…

2026/10/10 23:24:59 阅读更多 →
ADHD不是缺陷,而是可适配的认知操作系统

ADHD不是缺陷,而是可适配的认知操作系统

1. “I have ADHD”不是一句网络梗,而是一把打开理解之门的钥匙最近在多个内容平台刷到带#IHaveADHD标签的短视频,有人边叠衣服边突然开始拆解冰箱压缩机原理,有人对着Excel表格写诗,还有人用37种颜色标记同一份会议纪要——评论区…

2026/10/10 23:24:59 阅读更多 →
微信小程序+SpringBoot个人财务管理系统:毕业设计源码拆解与避坑指南

微信小程序+SpringBoot个人财务管理系统:毕业设计源码拆解与避坑指南

简介:基于微信小程序的个人财务管理系统毕业设计论文文档,完整呈现从选题意义、系统分析到技术实现的全过程,适合计算机相关专业学生作为毕业设计与论文写作参考。文档围绕Uni-weixin、Spring Boot与MySQL技术路线,前端以小程序页…

2026/10/10 23:24:59 阅读更多 →
PLC物料自动检测与分拣系统设计与调试实战指南

PLC物料自动检测与分拣系统设计与调试实战指南

做毕业设计或者接非标自动化项目的时候,物料自动检测与分拣系统基本是绕不开的经典课题。这个标题看着很长,其实拆开就三个关键词:PLC、物料检测、分拣系统。说白了就是用可编程逻辑控制器当大脑,配合各类传感器当眼睛&#xff0c…

2026/10/10 23:23:58 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:25 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 1:36:08 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →