open-spaced-repetition / fsrs4anki

A modern Anki custom scheduling based on Free Spaced Repetition Scheduler algorithm
https://github.com/open-spaced-repetition/fsrs4anki/wiki
MIT License
2.8k stars 137 forks source link

[Question] Is a linear function for the new stabiliity after a successful review the best function to model stability increases? #445

Closed kuroahna closed 1 year ago

kuroahna commented 1 year ago

Research

Enter an [x] character to confirm the points below:

Question

I searched the issues in the tracker and couldn't find any discussion about this (sorry if I missed it), but I've been comparing Anki SM-2 and FSRS and wondering if a linear function is the best function to model stability/interval increases.

To keep the functions simple, for a given card, if we assume that we answer Good every time, and assume that $t = 0$ where $t$ is the number of days since the last review, and let $x$ be the current interval for a card in days, then Anki's scheduling algorithm can be written as

$$f(x) = 2.5x$$

One downside of Anki's scheduling algorithm in this case is that the current interval for a card keeps increasing by 2.5 every time we press Good. According to Supermemo on memory stability, he states that

The higher the stability, the lesser the stability increase at review (see: Stabilization decay). As the name implies, the memory tends to stabilize in the long-term storage.

This makes sense, as I don't think the interval for a card should grow that fast as the interval increases. For example, for a card with an interval of 1000 days (~2.74 years), it will be scheduled in 2500 days (~6.85 years).

On the other hand, FSRS keeps this in mind. According to the FSRS wiki

The larger the value of S, the smaller the SInc value. This means that the higher the stability of the memory, the harder it becomes to make the memory even more stable.

If we use the default FSRS v4 parameters

$$w = [0.4, 0.6, 2.4, 5.8, 4.93, 0.94, 0.86, 0.01, 1.49, 0.14, 0.94, 2.18, 0.05, 0.34, 1.26, 0.29, 2.61]$$

and fix $D = 5$ and $G = 3$, and let $t = S$ so that $R(t, S) = 0.9$, then the $S'_r$ function

$$S'_r(D, S, R, G) = S \cdot (e^{w_8} \cdot (11 - D) \cdot S^{-w9} \cdot (e^{w_{10} \cdot (1 - R) } - 1) \cdot w_{15} (\text{if} G = 2) \cdot w\{16} (\text{if} G = 4) + 1)$$

becomes

$$S'_r(5, S, 0.9, 3) = S \cdot (e^{1.49} \cdot (11 - 5) \cdot S^{-0.14} \cdot (e^{0.94 \cdot (1 - 0.9) } - 1) + 1)$$

which we can graph the 2 linear functions and get

image

Where if $S = 1000$ days, then $S'_r = 1997.584$ days

We can also see that the rate of change for FSRS decreases as the current interval increases, and the rate of change for Anki SM-2 is a constant 2.5

image

However, I was wondering if a non-linear function would provide a better fit from the data points in our revlogs (ie, a curve of best fit instead of line of best fit)? Has there been any research/tests done in this area? If there has, I'd be interested in seeing it!

L-M-Sherlock commented 1 year ago

If the linear function is better, $w_9$ will be zero after optimization.

Expertium commented 1 year ago

Well, not quite, since in the current implementation w_9 cannot be lower than 0.1. By the way, I was thinking that perhaps we should loosen that one up as well (remember how recently I suggested loosening the clamps for w[8] and w[10]?), and change w[9] = w[9].clamp(0.1, 0.8) to something like w[9] = w[9].clamp(0.03, 1.0). @kuroahna I'm not entirely sure what you are proposing. How exactly should the formula be modified? Something like this? image

kuroahna commented 1 year ago

Well, not quite, since in the current implementation w_9 cannot be lower than 0.1.

Oh, that explains why my w_9 is stuck at 0.1 and doesn't go any lower.

w = [2.7397, 4.0114, 7.1071, 34.6658, 5.2058, 0.6632, 0.9231, 0.0873, 0.7611, 0.1, 0.978, 2.1256, 0.1662, 0.4333, 1.3935, 0.0009, 7.9765]

I'm not entirely sure what you are proposing. How exactly should the formula be modified? Something like this?

I had a misunderstanding with the formula. I thought $S'_r$ was a linear function since $e = 2.71 \dots$, and

$$w = [0.4, 0.6, 2.4, 5.8, 4.93, 0.94, 0.86, 0.01, 1.49, 0.14, 0.94, 2.18, 0.05, 0.34, 1.26, 0.29, 2.61]$$

and fix $D = 5$ and $G = 3$, and let $t = S$ so that $R(t, S) = 0.9$, then I thought the $S'_r$ function

$$ \begin{align} S'_r(D, S, R, G) &= S \cdot (e^{w_8} \cdot (11 - D) \cdot S^{-w9} \cdot (e^{w_{10} \cdot (1 - R) } - 1) \cdot w_{15} (\text{if} G = 2) \cdot w\{16} (\text{if} G = 4) + 1) \ S'_r(5, S, 0.9, 3) &= S \cdot (e^{1.49} \cdot (11 - 5) \cdot S^{-0.14} \cdot (e^{0.94 \cdot (1 - 0.9) } - 1) + 1) \ &= S \cdot (e^{1.49} \cdot 6 \cdot S^{-0.14} \cdot (e^{0.094} - 1) + 1) \end{align} $$

is a linear function of the form $y = mx + b$ because $e\^{1.49}$ is a constant, $6$ is a constant, $e^{0.094} - 1$ is a constant, and $+1$ is a constant. That is, if we let $a = e^{1.49} \cdot 6$, $b = e^{0.094} - 1$ and $c = 1$, then we have

$$ \begin{align} S'_r(5, S, 0.9, 3) &= S \cdot (a \cdot S^{-0.14} \cdot b + c) \end{align} $$

I thought the $(a \cdot S^{-0.14} \cdot b + c)$ was a constant, so we'd have something of the form $y = mx + b$ (linear function), but that's not the case since we have the term $S^{-0.14}$ which makes the function non-linear.

I was playing around with my revlog and was trying to find if I can find a function that represents my "memory model" better than stock Anki SM-2 by using a line or curve of best fit (and keep the scheduling function simple), and compare the scheduling results with FSRS, but it wasn't any better since the line of best fit basically just gave me back $y = 2.5x$.

Here's my sample code:

from zipfile import ZipFile
import os
import sqlite3
import numpy as np
import matplotlib.pyplot as plt

if not os.path.exists("collection.anki21"):
    with ZipFile("./collection.colpkg", 'r') as zip:
        zip.extractall()

connection = sqlite3.connect("collection.anki21")
cursor = connection.cursor()
# Get reviews only, and ensure the intervals we get aren't the
# learning/relearn steps, where negative values indicate the interval in
# seconds, rather than days
result_set = cursor.execute("SELECT lastIvl, ivl FROM revlog WHERE type = 1 AND lastIvl >= 0 AND ivl >= 0").fetchall()
x = []
y = []
for result in result_set:
    x.append(result[0])
    y.append(result[1])
x = np.array(x)
y = np.array(y)

m, b = np.polyfit(x, y, 1)
line_of_best_fit = m * x + b

plt.scatter(x, y)
plt.plot(x, line_of_best_fit, color="red", label=f"y = {m:.2f}x + {b:.2f}")
plt.xlabel("Last interval (days)")
plt.ylabel("Interval (days)")
plt.legend()
plt.show()

Untitled

I think the line of best fit was $y = 2.51x - 4.17$ (essentially $y = 2.5x$) since I'm just looking at the lastIvl and ivl, and not really taking into account other things like FSRS does.

However, I'm wondering if there's still some kind of issue here? My trained weights are

w = [2.7397, 4.0114, 7.1071, 34.6658, 5.2058, 0.6632, 0.9231, 0.0873, 0.7611, 0.1, 0.978, 2.1256, 0.1662, 0.4333, 1.3935, 0.0009, 7.9765]

using FSRS Optimizer v4.5.5. If we loosen the clamp for w[9] from [0.1, 0.8] to [0.03, 1.0], then I think my w[9] will go lower than 0.1 (it'll probably go really close to 0) And even without loosening the clamp, the stability function is still almost linear (w[9] is 0.1). In other words, for my weights (or even default weights), graphing the stability/interval function between FSRS and SRS is still "linear"

image

From Supermemo,

The higher the stability, the lesser the stability increase at review (see: Stabilization decay). As the name implies, the memory tends to stabilize in the long-term storage.

I interpreted the "the higher the stability, the lesser the stability increase" to mean that as the stability increases, it should approach some kind of "limit", rather than grow infinitely. In other words, some kind of logarithmic or sigmoid function, like in the graphs here

image

We can see that the red line (Anki SM2) and blue line (FSRS) has the interval growing infinitely rather than approach some kind of limit, whereas the purple line approaches a limit (28.5 here), and the green line technically grows infinitely, but it is really slow.

I was wondering if FSRS has done any research here, whether a linear function or non-linear function better models our memory stability and if it should have some kind of "limit" rather than grow infinitely and have some kind of logarithmic/exponential growth.

I feel like there might be a possible issue with FSRS. Even though it has the $S\^{-w_9}$ term to make it non-linear, the way it's training on my data makes it insignificant

Also, changing the values for $w_9$ between 0 and 1 in the graph still makes it grow infinitely at a fast pace (linearly), rather than slow down in growth as x approaches to infinity. So I'm wondering if there could be any improvements here in the stability function to account for this observation

Expertium commented 1 year ago

I interpreted the "the higher the stability, the lesser the stability increase" to mean that as the stability increases, it should approach some kind of "limit",

No, S itself can increase infinitely, but the rate at which it increases approaches a limit, yes.

Expertium commented 1 year ago

Also, you won't learn anything useful from this chart since it depends on Anki settings. You're not graphing "previous optimal interval vs new optimal interval", you're graphing "previous interval given by Anki vs new interval given by Anki". image

Expertium commented 1 year ago

Also, for the next 6-12 months, it's unlikely that any major changes to the algorithm will be made. The reason is that each change to the algorithm will require changing the scheduler code and the optimizer code and the helper add-on code. The more versions there are, the more code will have to be added to the helper add-on to support all of those versions, and the higher the chances that users will be confused and do something like using the parameters from one version with the scheduler code of another version. So a new version of FSRS won't be released for a while. Then there is also the fact that, right now, neither I nor Sherlock have any good ideas on how to improve the formulas. Well, I do have some ideas, but they would require very major changes to the code and would be a nightmare to implement.

kuroahna commented 1 year ago

No, S itself can increase infinitely, but the rate at which it increases approaches a limit, yes. Also, you won't learn anything useful from this chart since it depends on Anki settings. You're not graphing "previous optimal interval vs new optimal interval", you're graphing "previous interval given by Anki vs new interval given by Anki".

Right, thanks, that makes sense, I should be looking at the rate of change, and not the raw intervals. Anki SM-2 has a rate of change of 2.5 in the above examples, but FSRS's rate of change properly decreases and approaches a limit as x approaches infinity, which is exactly what we wanted

L-M-Sherlock commented 1 year ago

I have researched a lot about the stability increase:

image image image

I recommend reading my papers: