From a85bb2a55141c91681e3d05df943c8a63ace5abf Mon Sep 17 00:00:00 2001 From: Aner Zakobar Date: Wed, 15 Jul 2026 20:58:17 +0300 Subject: [PATCH] Thesis - wip --- bibliography/thesis.bib | 28 + content/appendixs/appendix_gauss_grad.tex | 68 +++ content/appendixs/appendix_kde_bisection.tex | 30 + content/appendixs/appendix_kde_grad.tex | 142 +++++ content/appendixs/appendix_kde_nr.tex | 28 + content/appendixs/appendix_kde_sigmoid.tex | 70 +++ .../method/figures/density_fit_comparison.png | Bin 0 -> 77483 bytes .../method/figures/density_fit_comparison.py | 181 ++++++ .../figures/threshold_weighting_gaussian.png | Bin 0 -> 87573 bytes .../figures/threshold_weighting_gaussian.py | 123 ++++ content/method/method.tex | 537 +++++------------- content/related_work/related_work.tex | 128 ++++- main.tex | 27 +- 13 files changed, 963 insertions(+), 399 deletions(-) create mode 100644 content/appendixs/appendix_gauss_grad.tex create mode 100644 content/appendixs/appendix_kde_bisection.tex create mode 100644 content/appendixs/appendix_kde_grad.tex create mode 100644 content/appendixs/appendix_kde_nr.tex create mode 100644 content/appendixs/appendix_kde_sigmoid.tex create mode 100644 content/method/figures/density_fit_comparison.png create mode 100644 content/method/figures/density_fit_comparison.py create mode 100644 content/method/figures/threshold_weighting_gaussian.png create mode 100644 content/method/figures/threshold_weighting_gaussian.py diff --git a/bibliography/thesis.bib b/bibliography/thesis.bib index 47bea7f..c5cd624 100644 --- a/bibliography/thesis.bib +++ b/bibliography/thesis.bib @@ -9,6 +9,15 @@ publisher={Wiley} } +@book{silverman1986density, + title={Density Estimation for Statistics and Data Analysis}, + author={Silverman, B. W.}, + year={1986}, + publisher={Chapman and Hall}, + address={London}, + series={Chapman \& Hall/CRC Monographs on Statistics and Applied Probability} +} + @article{botev2010kde, title={Kernel density estimation via diffusion}, author={Botev, Z. I. and Grotowski, J. F. and Kroese, D. P.}, @@ -49,6 +58,25 @@ publisher={Springer} } +@article{xie2024wsauc, + title={Weakly Supervised {AUC} Optimization: A Unified Partial {AUC} Approach}, + author={Xie, Zheng and Liu, Yu and He, Hao-Yuan and Li, Ming and Zhou, Zhi-Hua}, + journal={IEEE Transactions on Pattern Analysis and Machine Intelligence}, + year={2024}, + doi={10.1109/TPAMI.2024.3357814}, + eprint={2305.14258}, + archivePrefix={arXiv} +} + +@inproceedings{wu2025preserving, + title={Preserving {AUC} Fairness in Learning with Noisy Protected Groups}, + author={Wu, Mingyang and Lin, Li and Zhang, Wenbin and Wang, Xin and Yang, Zhenhuan and Hu, Shu}, + booktitle={Proceedings of the 42nd International Conference on Machine Learning}, + year={2025}, + eprint={2505.18532}, + archivePrefix={arXiv} +} + @article{altman1989solving, title={Solving the jigsaw puzzle problem in linear time}, author={Altman, Tom}, diff --git a/content/appendixs/appendix_gauss_grad.tex b/content/appendixs/appendix_gauss_grad.tex new file mode 100644 index 0000000..0f6929d --- /dev/null +++ b/content/appendixs/appendix_gauss_grad.tex @@ -0,0 +1,68 @@ +We derive the gradient of \eqref{eq:roll-tpr-at-fpr-gaussian} with respect to +$f_\theta(\mathbf{x}_i)$, instantiating the general structure~\eqref{eq:roll-gradient} +for the Gaussian case. Throughout, $\tau = \hat{F}_0^{-1}(1-\alpha) = +\mu_0 + \sigma_0\sqrt{2}\,\operatorname{ierf}(1-2\alpha)$. + +\paragraph{Case $y_i = 1$.} + +The score $f_\theta(\mathbf{x}_i)$ enters through $\mu_1$ and $\sigma_1$. +Differentiating $\hat{F}_1(\tau) = \frac{1}{2}\bigl[1+\operatorname{erf}\!\bigl(\frac{\tau-\mu_1}{\sigma_1\sqrt{2}}\bigr)\bigr]$: + +\[ + \dfrac{\partial \hat{F}_1(\hat{F}_0^{-1}(1-\alpha))}{\partial \mu_1} = + -\frac{1}{\sigma_1\sqrt{2\pi}}\exp\!\left(-\frac{(\tau - \mu_1)^2}{2\sigma_1^2}\right) +\] + +\[ + \dfrac{\partial \hat{F}_1(\hat{F}_0^{-1}(1-\alpha))}{\partial \sigma_1} = + \frac{\mu_1 - \tau}{\sigma_1^2\sqrt{2\pi}}\exp\!\left(-\frac{(\tau - \mu_1)^2}{2\sigma_1^2}\right) +\] + +Combined with $\frac{\partial \mu_1}{\partial f_\theta(\mathbf{x}_i)} = \frac{1}{|\mathcal{B}_1|}$ +and $\frac{\partial \sigma_1}{\partial f_\theta(\mathbf{x}_i)} = \frac{f_\theta(\mathbf{x}_i)-\mu_1}{|\mathcal{B}_1|\sigma_1}$, +the chain rule gives: + +\begin{equation} + \dfrac{\partial \hat{F}_1(\hat{F}_0^{-1}(1-\alpha))}{\partial f_{\theta}(\mathbf{x}_i)} + = -\frac{1}{|\mathcal{B}_1|\,\sigma_1\sqrt{2\pi}} + \exp\!\left(-\frac{(\tau - \mu_1)^2}{2\sigma_1^2}\right) + \left(1 + \frac{(\tau - \mu_1)(f_\theta(\mathbf{x}_i) - \mu_1)}{\sigma_1^2}\right) + \label{eq:gauss-grad-y1} +\end{equation} + +\paragraph{Case $y_i = 0$.} + +The score $f_\theta(\mathbf{x}_i)$ affects the loss only through $\tau$. By the chain rule: + +\[ + \frac{\partial \hat{F}_1(\tau)}{\partial f_\theta(\mathbf{x}_i)} + = \underbrace{\frac{\partial \hat{F}_1(\tau)}{\partial \tau}}_{\text{PDF of class 1 at }\tau} + \cdot \frac{\partial \tau}{\partial f_\theta(\mathbf{x}_i)} +\] + +The first factor is the Gaussian PDF at $\tau$: +\[ + \frac{\partial \hat{F}_1(\tau)}{\partial \tau} + = \frac{1}{\sigma_1\sqrt{2\pi}}\exp\!\left(-\frac{(\tau - \mu_1)^2}{2\sigma_1^2}\right) +\] + +For the second factor, since $\tau = \mu_0 + \sigma_0\sqrt{2}\,\operatorname{ierf}(1-2\alpha)$: +$\frac{\partial\tau}{\partial\mu_0}=1$ and +$\frac{\partial\tau}{\partial\sigma_0}=\frac{\tau-\mu_0}{\sigma_0}$. +Combined with $\frac{\partial\mu_0}{\partial f_\theta(\mathbf{x}_i)}=\frac{1}{|\mathcal{B}_0|}$ +and $\frac{\partial\sigma_0}{\partial f_\theta(\mathbf{x}_i)}=\frac{f_\theta(\mathbf{x}_i)-\mu_0}{|\mathcal{B}_0|\sigma_0}$: +\[ + \frac{\partial\tau}{\partial f_\theta(\mathbf{x}_i)} + = \frac{1}{|\mathcal{B}_0|}\!\left(1+\frac{(\tau-\mu_0)(f_\theta(\mathbf{x}_i)-\mu_0)}{\sigma_0^2}\right) +\] + +Therefore: +\begin{equation} + \dfrac{\partial \hat{F}_1(\hat{F}_0^{-1}(1-\alpha))}{\partial f_\theta(\mathbf{x}_i)} + = \frac{1}{|\mathcal{B}_0|\,\sigma_1\sqrt{2\pi}} + \exp\!\left(-\frac{(\tau - \mu_1)^2}{2\sigma_1^2}\right) + \left(1 + \frac{(\tau - \mu_0)(f_\theta(\mathbf{x}_i) - \mu_0)}{\sigma_0^2}\right) + \label{eq:gauss-grad-y0} +\end{equation} + +Substituting \eqref{eq:gauss-grad-y1} and \eqref{eq:gauss-grad-y0} into \eqref{eq:roll-gradient} yields \eqref{eq:gauss-grad-combined}. diff --git a/content/appendixs/appendix_kde_bisection.tex b/content/appendixs/appendix_kde_bisection.tex new file mode 100644 index 0000000..7c930f2 --- /dev/null +++ b/content/appendixs/appendix_kde_bisection.tex @@ -0,0 +1,30 @@ +We describe the bisection procedure used to compute $\tau = \hat{F}_0^{-1}(1-\alpha;\mathcal{B}_0)$ +in the KDE-ROLL forward pass (\Cref{sec:roll-kde-forward}). + +\paragraph{Bracket initialisation.} +Because $\sigma(u;\,v) \to 0$ exponentially as $u \to -\infty$ and $\sigma(u;\,v) \to 1$ +as $u \to +\infty$, with tails decaying within roughly $10/v_0$ of the data range, the +interval +\[ + \mathrm{lo} = \min(\mathbf{s}^{(0)}) - \tfrac{10}{v_0}, + \qquad + \mathrm{hi} = \max(\mathbf{s}^{(0)}) + \tfrac{10}{v_0} +\] +is guaranteed to satisfy $\hat{F}_0(\mathrm{lo}) < 1-\alpha < \hat{F}_0(\mathrm{hi})$. + +\paragraph{Bisection iterations.} +At each step we evaluate the midpoint, +\[ + \tau_{\mathrm{mid}} = \tfrac{1}{2}(\mathrm{lo} + \mathrm{hi}), +\] +and update the bracket: +\[ + \begin{cases} + \mathrm{lo} \leftarrow \tau_{\mathrm{mid}} & \text{if } \hat{F}_0(\tau_{\mathrm{mid}};\,\mathcal{B}_0) < 1-\alpha, \\ + \mathrm{hi} \leftarrow \tau_{\mathrm{mid}} & \text{otherwise.} + \end{cases} +\] +Iteration continues until $\lvert\hat{F}_0(\tau_{\mathrm{mid}};\,\mathcal{B}_0)-(1-\alpha)\rvert < \varepsilon$ +(with $\varepsilon = 10^{-4}$), or until a maximum iteration count is reached. +The method converges unconditionally and requires no derivative evaluation, in contrast +to the Newton--Raphson alternative documented in Appendix~\ref{appendix:kde-nr}. diff --git a/content/appendixs/appendix_kde_grad.tex b/content/appendixs/appendix_kde_grad.tex new file mode 100644 index 0000000..b20ea72 --- /dev/null +++ b/content/appendixs/appendix_kde_grad.tex @@ -0,0 +1,142 @@ +We derive the KDE gradient, instantiating the general form~\eqref{eq:roll-gradient}. +Throughout, $\tau = \hat{F}_0^{-1}(1-\alpha;\mathcal{B}_0)$ and bandwidths $v_0, v_1$ +are as defined in \Cref{sec:kde-bandwidth}. + +\paragraph{Case $y_i = 1$: expanding the KDE sum.} + +When $\mathbf{x}_i \in \mathcal{B}_1$, the score $f_\theta(\mathbf{x}_i)$ appears directly +in $\hat{F}_1$ and has no effect on $\tau$. Expanding the KDE CDF: +% +\[ + \dfrac{\partial \hat{F}_1\!\left(\hat{F}_0^{-1}(1-\alpha)\right)}{\partial f_{\theta}(\mathbf{x}_i)} + = \frac{\partial}{\partial f_{\theta}(\mathbf{x}_i)} + \frac{1}{|\mathcal{B}_1|}\sum_{\mathbf{x}_j \in \mathcal{B}_1} + \sigma_1\!\left(\tau - f_{\theta}(\mathbf{x}_j)\right) +\] +% +Separating the $j = i$ term (the only one depending on $f_\theta(\mathbf{x}_i)$): +% +\[ + = \frac{\partial}{\partial f_{\theta}(\mathbf{x}_i)}\!\left( + \sum_{\substack{\mathbf{x}_j \in \mathcal{B}_1 \\ j \neq i}} + \frac{\sigma_1\!\left(\tau - f_{\theta}(\mathbf{x}_j)\right)}{|\mathcal{B}_1|} + \;+\; + \frac{\sigma_1\!\left(\tau - f_{\theta}(\mathbf{x}_i)\right)}{|\mathcal{B}_1|} + \right) +\] +% +The first sum is constant in $f_\theta(\mathbf{x}_i)$. Applying the chain rule to the +last term with $\partial(\tau - f_\theta(\mathbf{x}_i))/\partial f_\theta(\mathbf{x}_i) = -1$: +% +\begin{equation} + \frac{\partial \hat{F}_1(\hat{F}_0^{-1}(1-\alpha))}{\partial f_{\theta}(\mathbf{x}_i)} + = -\frac{1}{|\mathcal{B}_1|}\sigma_1'(\tau - f_{\theta}(\mathbf{x}_i)) + \label{eq:kde-grad-y1} +\end{equation} + +\paragraph{Case $y_i = 0$: derivative of $\hat{F}_1$ with respect to $\tau$.} + +Differentiating the KDE CDF with respect to $\tau$: +% +\[ + \frac{\partial \hat{F}_1\!\left(\hat{F}_0^{-1}(1-\alpha)\right)}{\partial \hat{F}_0^{-1}(1-\alpha)} + = \frac{\partial}{\partial \tau} + \frac{1}{|\mathcal{B}_1|}\sum_{\mathbf{x}_j \in \mathcal{B}_1} + \sigma_1\!\left(\tau - f_{\theta}(\mathbf{x}_j)\right) +\] +% +Since $\partial(\tau - f_\theta(\mathbf{x}_j))/\partial\tau = +1$ for every $j$, +the chain rule gives: +% +\begin{equation} + \frac{\partial \hat{F}_1(\hat{F}_0^{-1}(1-\alpha))}{\partial \hat{F}_0^{-1}(1-\alpha)} + = +\frac{1}{|\mathcal{B}_1|}\sum_{\mathbf{x}_j \in \mathcal{B}_1}\sigma_1'(\tau - f_{\theta}(\mathbf{x}_j)) + \label{eq:kde-dF1-dtau} +\end{equation} + +\paragraph{Case $y_i = 0$: derivative of $\tau$ with respect to $f_\theta(\mathbf{x}_i)$.} + +Since $\tau = \hat{F}_0^{-1}(1-\alpha;\mathcal{B}_0)$ is computed numerically, we apply the \emph{inverse function theorem}: if $h$ has inverse $g$, +then $g'(y) = 1/h'(g(y))$. + +We view $\hat{F}_0^{-1}(1-\alpha;\mathcal{B}_0)$ as a function of $f_\theta(\mathbf{x}_i)$ +and find its inverse. From the defining equation +$|\mathcal{B}_0|\cdot(1-\alpha) = \sum_{\mathbf{x}_j \in \mathcal{B}_0} +\sigma_0(\tau - f_\theta(\mathbf{x}_j))$, solving for $f_\theta(\mathbf{x}_i)$: +% +\[ + f_\theta(\mathbf{x}_i) + = \tau - \sigma_0^{-1}\!\!\left( + |\mathcal{B}_0|\cdot(1-\alpha) + - \sum_{\substack{\mathbf{x}_j \in \mathcal{B}_0 \\ j \neq i}} + \sigma_0\!\left(\tau - f_{\theta}(\mathbf{x}_j)\right) + \right) +\] +% +Differentiating this expression with respect to $\tau$ and applying the chain rule: +% +\[ + \frac{\partial f_\theta(\mathbf{x}_i)}{\partial \tau} + = 1 + \sigma_0^{-1}{}'\!\!\left(\cdots\right) + \cdot + \sum_{\substack{\mathbf{x}_j \in \mathcal{B}_0 \\ j \neq i}} + \sigma_0'\!\left(\tau - f_{\theta}(\mathbf{x}_j)\right) +\] +% +(the leading $+1$ comes from differentiating $\tau$; the second term from differentiating +through $\sigma_0^{-1}$). By the inverse function theorem: +% +\[ + \frac{\partial \hat{F}_0^{-1}(1-\alpha ; \mathcal{B}_0)}{\partial f_\theta(\mathbf{x}_i)} + = \frac{1}{\displaystyle + 1 + \sigma_0^{-1}{}'\!\!\left( + |\mathcal{B}_0|\cdot(1-\alpha) + - \sum_{j \neq i}\sigma_0(\tau - f_\theta(\mathbf{x}_j)) + \right) + \cdot \sum_{j \neq i}\sigma_0'(\tau - f_\theta(\mathbf{x}_j))} +\] +% +Using $|\mathcal{B}_0|\cdot(1-\alpha) = \sum_j \sigma_0(\tau - f_\theta(\mathbf{x}_j))$, +the argument of $\sigma_0^{-1}{}'$ simplifies: +% +\[ + |\mathcal{B}_0|\cdot(1-\alpha) + - \sum_{j \neq i}\sigma_0(\tau - f_\theta(\mathbf{x}_j)) + = \sigma_0(\tau - f_\theta(\mathbf{x}_i)) +\] +% +Substituting and applying $\sigma_0^{-1}{}'(\sigma_0(u)) = 1/\sigma_0'(u)$, +then multiplying numerator and denominator by $\sigma_0'(\tau - f_\theta(\mathbf{x}_i))$: +% +\begin{equation} + \frac{\partial \hat{F}_0^{-1}(1-\alpha ; \mathcal{B}_0)}{\partial f_\theta(\mathbf{x}_i)} = + \frac{\sigma_0'(\tau - f_{\theta}(\mathbf{x}_i))}{\displaystyle\sum_{\mathbf{x}_j \in \mathcal{B}_0}\sigma_0'(\tau - f_{\theta}(\mathbf{x}_j))} + \label{eq:kde-grad-tau} +\end{equation} + +\paragraph{Efficient computation via the sigmoid identity.} + +Direct evaluation of \eqref{eq:kde-grad-tau} requires computing $\sigma_0'$ for every +point — potentially unstable when a point is far from $\tau$. For the sigmoid kernel, +the identity + +\begin{equation} + \sigma(u;\,v)\,\bigl(1 - \sigma(u;\,v)\bigr) = \frac{\sigma'(u;\,v)}{v} + \label{eq:sigmoid-identity} +\end{equation} + +(proved by direct substitution: both sides equal $\exp(-v|u|)/(1+\exp(-v|u|))^2$) +allows $v_0$ to cancel between numerator and denominator, so the ratio is expressed +entirely in terms of sigmoid values already cached from the forward pass: + +\begin{equation} + \frac{\partial \hat{F}_0^{-1}(1-\alpha ; \mathcal{B}_0)}{\partial f_\theta(\mathbf{x}_i)} + = + \frac{\sigma_0(\tau-f_\theta(\mathbf{x}_i))\,\bigl(1-\sigma_0(\tau-f_\theta(\mathbf{x}_i))\bigr)} + {\displaystyle\sum_{\mathbf{x}_j \in \mathcal{B}_0} + \sigma_0(\tau-f_\theta(\mathbf{x}_j))\,\bigl(1-\sigma_0(\tau-f_\theta(\mathbf{x}_j))\bigr)} + \label{eq:kde-grad-tau-efficient} +\end{equation} + +Substituting \eqref{eq:kde-grad-y1}, \eqref{eq:kde-dF1-dtau}, and \eqref{eq:kde-grad-tau} +into \eqref{eq:roll-gradient} yields \eqref{eq:kde-grad-combined}. diff --git a/content/appendixs/appendix_kde_nr.tex b/content/appendixs/appendix_kde_nr.tex new file mode 100644 index 0000000..7e03f70 --- /dev/null +++ b/content/appendixs/appendix_kde_nr.tex @@ -0,0 +1,28 @@ +An earlier version of the implementation used Newton--Raphson to invert the KDE CDF +instead of bisection (\Cref{sec:roll-kde-forward}). We document it here as a reference +alternative. + +\paragraph{Method.} +To find $\tau = \hat{F}_0^{-1}(1-\alpha;\mathcal{B}_0)$, choose an initial guess $\tau_0$ +and iterate: +\begin{equation} + \tau_{n+1} = \tau_n + - \frac{\hat{F}_0(\tau_n;\,\mathcal{B}_0) - (1-\alpha)} + {\dfrac{\partial\hat{F}_0(\tau_n;\,\mathcal{B}_0)}{\partial\tau}}, + \label{eq:kde-nr-step} +\end{equation} +where the denominator is the KDE density evaluated at $\tau_n$: +\[ + \frac{\partial\hat{F}_0(\tau_n;\,\mathcal{B}_0)}{\partial\tau} + = \frac{1}{|\mathcal{B}_0|}\sum_{\mathbf{x}_j\in\mathcal{B}_0} + \sigma_0'(\tau_n - f_\theta(\mathbf{x}_j)). +\] +Iteration continues until +$\lvert\hat{F}_0(\tau_n;\,\mathcal{B}_0)-(1-\alpha)\rvert < \varepsilon$. + +\paragraph{Limitations.} +Newton--Raphson requires evaluating $\sigma_0'$ at every step and can diverge if +$\tau_0$ is far from the root or if the KDE density is very small near the target +quantile (e.g.\ early in training when scores cluster tightly and $v_0$ is large). +These failure modes motivated the switch to bisection, which requires no derivative +evaluation in the forward pass and is guaranteed to converge given a valid bracket. diff --git a/content/appendixs/appendix_kde_sigmoid.tex b/content/appendixs/appendix_kde_sigmoid.tex new file mode 100644 index 0000000..e62b23e --- /dev/null +++ b/content/appendixs/appendix_kde_sigmoid.tex @@ -0,0 +1,70 @@ +We instantiate the KDE gradient~\eqref{eq:kde-grad-combined} for the logistic sigmoid +kernel used in our implementation. + +\paragraph{Kernel definition.} + +\begin{equation} + \sigma(x ; v) = \frac{1}{1 + \exp(-vx)}, + \qquad + \sigma'(x ; v) = \frac{v\,\exp(-v|x|)}{\bigl(1 + \exp(-v|x|)\bigr)^{2}} + \label{eq:sigmoid-kernel} +\end{equation} + +where $v > 0$ is the bandwidth parameter. The derivative uses $|x|$ rather than $x$: +since $\sigma'$ is even, both forms are mathematically identical, but $\exp(-v|x|) \to 0$ +as $|x| \to \infty$ whereas $\exp(-vx) \to \infty$ for $x \to -\infty$, so the $|x|$ +form avoids floating-point overflow when scores fall well below $\tau$. + +\paragraph{Forward pass.} + +Substituting \eqref{eq:sigmoid-kernel} into the KDE CDF: +% +\begin{equation} + \hat{F}_{k}(\tau ; \mathbf{s}^{(k)}) = + \frac{1}{|\mathcal{B}_k|} + \sum_{\mathbf{x}_j \in \mathcal{B}_k} + \frac{1}{1 + \exp\!\bigl(-v_k\bigl(\tau - f_\theta(\mathbf{x}_j)\bigr)\bigr)} + \label{eq:kde-sigmoid-cdf} +\end{equation} +% +The derivative of $\hat{F}_k$ with respect to $\tau$ — used in Newton--Raphson inversion +and in the gradient — is: +% +\begin{equation} + \frac{\partial \hat{F}_{k}(\tau)}{\partial \tau} + = + \frac{1}{|\mathcal{B}_k|} + \sum_{\mathbf{x}_j \in \mathcal{B}_k} + \frac{v_k\,\exp\!\bigl(-v_k\bigl|\tau - f_\theta(\mathbf{x}_j)\bigr|\bigr)} + {\Bigl(1 + \exp\!\bigl(-v_k\bigl|\tau - f_\theta(\mathbf{x}_j)\bigr|\bigr)\Bigr)^{2}} + \label{eq:kde-sigmoid-pdf} +\end{equation} + +\paragraph{Gradient.} + +Define the shorthand $\varphi_k(u) = \sigma'(u ; v_k)$: +\begin{equation} + \varphi_k(u) \;=\; + \frac{v_k\,\exp(-v_k|u|)}{\bigl(1+\exp(-v_k|u|)\bigr)^{2}} + \label{eq:sigmoid-phi} +\end{equation} + +Substituting \eqref{eq:sigmoid-kernel} into \eqref{eq:kde-grad-combined}: + +\begin{equation} + \frac{\partial \mathcal{L}_{\text{ROLL-TPR@FPR}}}{\partial f_\theta(\mathbf{x}_i)} = + \begin{cases} + -\dfrac{\varphi_1\!\left(\tau - f_\theta(\mathbf{x}_i)\right)}{|\mathcal{B}_1|} + & \text{if } y_i = 1\\[14pt] + +\,\dfrac{\displaystyle\sum_{\mathbf{x}_j \in \mathcal{B}_1} + \varphi_1\!\left(\tau - f_\theta(\mathbf{x}_j)\right)}{|\mathcal{B}_1|} + \;\cdot\; + \dfrac{\varphi_0\!\left(\tau-f_\theta(\mathbf{x}_i)\right)} + {\displaystyle\sum_{\mathbf{x}_j \in \mathcal{B}_0} + \varphi_0\!\left(\tau-f_\theta(\mathbf{x}_j)\right)} + & \text{if } y_i = 0 + \end{cases} + \label{eq:kde-sigmoid-grad} +\end{equation} + +where $\tau = \hat{F}_0^{-1}(1-\alpha ; \mathcal{B}_0)$. diff --git a/content/method/figures/density_fit_comparison.png b/content/method/figures/density_fit_comparison.png new file mode 100644 index 0000000000000000000000000000000000000000..94bc73608c307954f70cdeba2dcdb63f393d1641 GIT binary patch literal 77483 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∋Ie&(OX%c{;8=(`ttezAeSVG69!`?8Q8(LB(r}i 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 R=S1Lj@3xX$q0Cd?{|oZ4nMMEr literal 0 HcmV?d00001 diff --git a/content/method/figures/density_fit_comparison.py b/content/method/figures/density_fit_comparison.py new file mode 100644 index 0000000..7a076be --- /dev/null +++ b/content/method/figures/density_fit_comparison.py @@ -0,0 +1,181 @@ +""" +Comparison of density estimators on real model output scores. + +For each class (negative / positive) plots four curves against the empirical CDF: + - ECDF — ground truth step function + - KDE (ISJ) — Gaussian-kernel KDE with Improved Sheather-Jones bandwidth + - Gaussian fit — MLE normal distribution + - Beta fit — sigmoid-transformed scores fitted with Beta MLE, CDF + mapped back to the original logit axis + +Data: test split of a ROLL model trained on the glass0 dataset. + +Run from the impl directory (KDEpy lives in that flake): + cd impl && nix develop --command python3 ../thesis/content/method/figures/density_fit_comparison.py +""" + +import sys, pickle +from pathlib import Path +import numpy as np +import matplotlib +matplotlib.use("Agg") +import matplotlib.pyplot as plt +from scipy.stats import norm, beta as sp_beta +from scipy.special import expit +from KDEpy import FFTKDE +from KDEpy.bw_selection import silvermans_rule, improved_sheather_jones + +# Resolve paths relative to this script's location so the script runs from anywhere. +_HERE = Path(__file__).resolve().parent # .../thesis/content/method/figures +_THESIS = _HERE.parents[2] # .../thesis +_IMPL = _THESIS.parent / "impl" # .../impl + +sys.path.insert(0, str(_IMPL)) # pickle needs 'import src.experiment' → impl/src/experiment.py + +# ── Config ────────────────────────────────────────────────────────────────── +RESULT_PKL = _IMPL / "results/glass0/2026-07-08-22-25/roll/0/test-res.pkl" +OUT_DIR = _HERE +SPLIT = "test" + +C_NEG = "#4477AA" +C_POS = "#CC6633" + +plt.rcParams.update({ + "text.usetex": False, + "mathtext.fontset": "cm", + "pdf.fonttype": 42, +}) + +# ── Load data ──────────────────────────────────────────────────────────────── +with open(RESULT_PKL, "rb") as f: + ep = pickle.load(f) + +res = ep.split_results[SPLIT] +yh = res.yh.astype(np.float64) # raw logit scores +y = res.y + +scores_neg = yh[y == 0] +scores_pos = yh[y == 1] + +print(f"Loaded {SPLIT} split: {len(scores_neg)} negatives, {len(scores_pos)} positives") +print(f"Score range: [{yh.min():.3f}, {yh.max():.3f}]") + + +# ── Helpers ────────────────────────────────────────────────────────────────── +def ecdf(scores): + """Return (x, p) for a step-function ECDF.""" + s = np.sort(scores) + p = np.arange(1, len(s) + 1) / len(s) + return s, p + + +def _kde_pdf(scores, x_grid, h): + pdf = FFTKDE(kernel="gaussian", bw=h).fit(scores).evaluate(x_grid) + dx = x_grid[1] - x_grid[0] + cdf = np.cumsum(pdf) * dx + cdf /= cdf[-1] + return cdf + +def kde_isj_cdf(scores, x_grid): + """ISJ bandwidth; Silverman fallback on failure.""" + data = scores[:, np.newaxis].astype(np.float64) + try: + h = float(improved_sheather_jones(data)) + except Exception: + h = float(silvermans_rule(data)) + return _kde_pdf(scores, x_grid, h) + +def kde_silverman_cdf(scores, x_grid): + h = float(silvermans_rule(scores[:, np.newaxis].astype(np.float64))) + return _kde_pdf(scores, x_grid, h) + + +def gauss_cdf(scores, x_grid): + loc, scale = norm.fit(scores) + return norm.cdf(x_grid, loc, scale) + + +def beta_cdf(scores, x_grid): + """Fit Beta in sigmoid space; evaluate CDF back on the logit x_grid.""" + s01 = expit(scores).clip(1e-6, 1 - 1e-6) + a, b, _, _ = sp_beta.fit(s01, floc=0, fscale=1) + return sp_beta.cdf(expit(x_grid), a, b) + + +# ── Shared x-grid (covers both classes with a small margin) ────────────────── +margin = 0.5 +x_lo = yh.min() - margin +x_hi = yh.max() + margin +x_grid = np.linspace(x_lo, x_hi, 2048) + + +# ── Compute all curves ─────────────────────────────────────────────────────── +neg_ecdf_x, neg_ecdf_p = ecdf(scores_neg) +neg_cdf_kde = kde_isj_cdf(scores_neg, x_grid) +neg_cdf_silverman = kde_silverman_cdf(scores_neg, x_grid) +neg_cdf_gauss = gauss_cdf(scores_neg, x_grid) +neg_cdf_beta = beta_cdf(scores_neg, x_grid) + +pos_ecdf_x, pos_ecdf_p = ecdf(scores_pos) +pos_cdf_kde = kde_isj_cdf(scores_pos, x_grid) +pos_cdf_silverman = kde_silverman_cdf(scores_pos, x_grid) +pos_cdf_gauss = gauss_cdf(scores_pos, x_grid) +pos_cdf_beta = beta_cdf(scores_pos, x_grid) + + +# ── Plot ───────────────────────────────────────────────────────────────────── +fig, (ax0, ax1) = plt.subplots( + 2, 1, figsize=(5.5, 4.8), sharex=True, + gridspec_kw={"height_ratios": [1, 1]}, +) +fig.subplots_adjust(hspace=0.08) + + +def _plot_class(ax, color, ecdf_x, ecdf_p, + cdf_isj, cdf_silverman, cdf_gauss, cdf_beta, label_prefix): + ax.step(ecdf_x, ecdf_p, + color=color, lw=1.0, alpha=0.55, where="post", + label="ECDF") + ax.plot(x_grid, cdf_isj, + color=color, lw=1.8, linestyle="-", + label="KDE (ISJ)") + ax.plot(x_grid, cdf_silverman, + color=color, lw=1.4, linestyle="-.", + label="KDE (Silverman)") + ax.plot(x_grid, cdf_gauss, + color=color, lw=1.4, linestyle="--", + label="Gaussian") + ax.plot(x_grid, cdf_beta, + color=color, lw=1.6, linestyle=":", + label="Beta") + ax.set_ylabel("CDF", fontsize=9) + ax.set_yticks([0.0, 0.25, 0.50, 0.75, 1.0]) + ax.set_yticklabels(["0", ".25", ".5", ".75", "1"], fontsize=7.5) + ax.tick_params(labelsize=8) + ax.spines[["top", "right"]].set_visible(False) + ax.text(0.97, 0.05, label_prefix, + transform=ax.transAxes, fontsize=8, + ha="right", va="bottom", color=color) + + +_plot_class(ax0, C_NEG, + neg_ecdf_x, neg_ecdf_p, + neg_cdf_kde, neg_cdf_silverman, neg_cdf_gauss, neg_cdf_beta, + r"Negative class ($y=0$)") + +_plot_class(ax1, C_POS, + pos_ecdf_x, pos_ecdf_p, + pos_cdf_kde, pos_cdf_silverman, pos_cdf_gauss, pos_cdf_beta, + r"Positive class ($y=1$)") + +ax0.legend(fontsize=7.5, loc="upper left", framealpha=0.88) +ax1.set_xlabel(r"Score $f_\theta(\mathbf{x})$", fontsize=9) +ax0.set_xlim(x_lo, x_hi) + +for path_suffix in ("pdf", "png"): + kw = {"bbox_inches": "tight"} + if path_suffix == "png": + kw["dpi"] = 180 + fig.savefig(OUT_DIR / f"density_fit_comparison.{path_suffix}", **kw) + +print(f"Saved to {OUT_DIR}/density_fit_comparison.{{pdf,png}}") diff --git a/content/method/figures/threshold_weighting_gaussian.png b/content/method/figures/threshold_weighting_gaussian.png new file mode 100644 index 0000000000000000000000000000000000000000..8519e5f1dbc59092f2ca92933091ad6c64fcccba GIT binary patch literal 87573 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�T4~A6s##!|vAH;hN9vmNk(tz7>aNJ;Csv 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 a%d2iRH97`42$|F2ze5KMw4Q35zW85%*I%Ik literal 0 HcmV?d00001 diff --git a/content/method/figures/threshold_weighting_gaussian.py b/content/method/figures/threshold_weighting_gaussian.py new file mode 100644 index 0000000..026f2dc --- /dev/null +++ b/content/method/figures/threshold_weighting_gaussian.py @@ -0,0 +1,123 @@ +""" +Illustrates the gradient locality property of Gaussian-ROLL. + +Upper panel: score distributions for both classes with fitted Gaussian PDFs + and operating threshold. +Lower panel: gradient magnitude per sample using the Gaussian gradient formula + (eq:gauss-grad-combined). + +Run from the thesis root: + nix develop --command python3 content/method/figures/threshold_weighting_gaussian.py +""" + +import numpy as np +from scipy import stats +import matplotlib +matplotlib.use("Agg") +import matplotlib.pyplot as plt + +plt.rcParams.update({ + "text.usetex": False, + "mathtext.fontset": "cm", + "pdf.fonttype": 42 +}) + +OUT_DIR = "content/method/figures" + +np.random.seed(7) + +# --- Data ------------------------------------------------------------------ +n = 120 +alpha = 0.25 # target FPR + +neg_scores = np.sort(np.random.normal(-0.6, 0.75, n)) +pos_scores = np.sort(np.random.normal(1.1, 0.80, n)) + +n0 = len(neg_scores) +n1 = len(pos_scores) + +# --- Gaussian MLE parameters ----------------------------------------------- +mu0, sigma0 = neg_scores.mean(), neg_scores.std() +mu1, sigma1 = pos_scores.mean(), pos_scores.std() + +# Threshold: (1-alpha)-quantile of negative class so that FPR = alpha +# (FPR = P(score > tau | y=0) = 1 - F_0(tau), so F_0(tau) = 1-alpha) +tau = stats.norm.ppf(1 - alpha, loc=mu0, scale=sigma0) + +# Shared scalar: pdf of positive class evaluated at the threshold +common = (1.0 / (sigma1 * np.sqrt(2 * np.pi))) * np.exp(-0.5 * ((tau - mu1) / sigma1) ** 2) + +# --- Gaussian ROLL gradients (eq:gauss-grad-combined) --------------------- +# y=1: -(1/n1) * common * (1 + (tau-mu1)*(s-mu1)/sigma1^2) +grad_pos_signed = -(1.0 / n1) * common * ( + 1 + (tau - mu1) * (pos_scores - mu1) / sigma1 ** 2 +) +grad_pos_abs = np.abs(grad_pos_signed) + +# y=0: +(1/n0) * common * (1 + (tau-mu0)*(s-mu0)/sigma0^2) +grad_neg_signed = (1.0 / n0) * common * ( + 1 + (tau - mu0) * (neg_scores - mu0) / sigma0 ** 2 +) +grad_neg_abs = np.abs(grad_neg_signed) + +# Gradient balance check (should be ~0) +print(f"Gradient balance: pos sum = {grad_pos_signed.sum():.6f}, " + f"neg sum = {grad_neg_signed.sum():.6f}, " + f"total = {(grad_pos_signed.sum() + grad_neg_signed.sum()):.2e}") + +# --- Smooth reference curves (continuous gradient functions) --------------- +x_ref = np.linspace(neg_scores.min() - 0.3, pos_scores.max() + 0.3, 400) +smooth_pos_abs = np.abs(-(1.0 / n1) * common * ( + 1 + (tau - mu1) * (x_ref - mu1) / sigma1 ** 2 +)) +smooth_neg_abs = np.abs((1.0 / n0) * common * ( + 1 + (tau - mu0) * (x_ref - mu0) / sigma0 ** 2 +)) + +# --- Plot ----------------------------------------------------------------- +C_NEG = "#4477AA" +C_POS = "#CC6633" +C_TAU = "#333333" + +fig, (ax1, ax2) = plt.subplots( + 2, 1, figsize=(5.5, 4.2), sharex=True, + gridspec_kw={"height_ratios": [1.3, 1.0]} +) +fig.subplots_adjust(hspace=0.06) + +# — Top: score distributions with fitted Gaussian PDFs — +ax1.hist(neg_scores, bins=20, density=True, alpha=0.35, color=C_NEG, + label=r"Negative class ($y=0$)") +ax1.hist(pos_scores, bins=20, density=True, alpha=0.35, color=C_POS, + label=r"Positive class ($y=1$)") +ax1.plot(x_ref, stats.norm.pdf(x_ref, mu0, sigma0), + color=C_NEG, linewidth=1.8, label=r"Fitted $\mathcal{N}(\mu_0,\sigma_0^2)$") +ax1.plot(x_ref, stats.norm.pdf(x_ref, mu1, sigma1), + color=C_POS, linewidth=1.8, label=r"Fitted $\mathcal{N}(\mu_1,\sigma_1^2)$") +ax1.axvline(tau, color=C_TAU, linestyle="--", linewidth=1.4, + label=rf"Threshold $\tau$ (FPR $=\alpha={alpha}$)") +ax1.set_ylabel("Density", fontsize=9) +ax1.set_yticks([]) +ax1.legend(fontsize=7, loc="upper right", framealpha=0.85) + +# — Bottom: gradient magnitudes — +ax2.scatter(neg_scores, grad_neg_abs, color=C_NEG, s=12, zorder=3, + alpha=0.75, label=r"$|\partial\mathcal{L}/\partial f_\theta(\mathbf{x})|$, $y=0$") +ax2.scatter(pos_scores, grad_pos_abs, color=C_POS, s=12, zorder=3, + alpha=0.75, label=r"$|\partial\mathcal{L}/\partial f_\theta(\mathbf{x})|$, $y=1$") +ax2.plot(x_ref, smooth_neg_abs, color=C_NEG, linewidth=1.2, alpha=0.55) +ax2.plot(x_ref, smooth_pos_abs, color=C_POS, linewidth=1.2, alpha=0.55) +ax2.axvline(tau, color=C_TAU, linestyle="--", linewidth=1.4) +ax2.set_ylabel("Gradient magnitude", fontsize=9) +ax2.set_xlabel(r"Score $f_\theta(\mathbf{x})$", fontsize=9) +ax2.set_yticks([]) +ax2.legend(fontsize=7.5, loc="upper right", framealpha=0.85) + +for ax in (ax1, ax2): + ax.tick_params(labelsize=8) + ax.spines[["top", "right"]].set_visible(False) + +out_base = f"{OUT_DIR}/threshold_weighting_gaussian" +fig.savefig(f"{out_base}.pdf", bbox_inches="tight") +fig.savefig(f"{out_base}.png", bbox_inches="tight", dpi=180) +print(f"Saved to {out_base}.{{pdf,png}}") diff --git a/content/method/method.tex b/content/method/method.tex index 6a18150..e1128d2 100644 --- a/content/method/method.tex +++ b/content/method/method.tex @@ -19,8 +19,8 @@ The positive and negative subsets of $\mathcal{D}$ are: Applying a threshold $\tau$ produces predictions $\hat{y} = \mathbf{1}[f_\theta(\mathbf{x}) > \tau]$. The \emph{true positive rate} (TPR) and \emph{false positive rate} (FPR) at $\tau$ are: \begin{align} - \operatorname{TPR}(\tau) &= P\!\bigl(f_\theta(\mathbf{x}) > \tau \mid y = 1\bigr), \\ - \operatorname{FPR}(\tau) &= P\!\bigl(f_\theta(\mathbf{x}) > \tau \mid y = 0\bigr). + \operatorname{TPR}(\alpha) &= P\!\bigl(f_\theta(\mathbf{x}) > \tau \mid y = 1\bigr), \\ + \operatorname{FPR}(\alpha) &= P\!\bigl(f_\theta(\mathbf{x}) > \tau \mid y = 0\bigr). \end{align} In our scenario, we either wish to learn $f_{\theta}$ in order to maximize $\operatorname{TPR}$ subject to a fixed $\operatorname{FPR}$, or vice versa. Our fixed $\operatorname{TPR}$ or $\operatorname{FPR}$ @@ -112,7 +112,8 @@ This necessitates a different approach, to make these calculations differentiabl The way to overcome this problem in differentiability is not to calculate the TPR and FPR directly, but to estimate them by fitting probability distributions to the score output of the model at -every step. Contiguous probability distributions are contiguous w.r.t their inputs. Additionally, we can calculate the TPR, FPR given the probability distributions CDF and ICDF functions. If we can gaurantee these functions to be differentiable, which proved to be the main challenge of this work, we can gaurantee this process to be differentiable. +every step. Contiguous probability distributions are contiguous w.r.t their defining parameters, and a derivation of the parameters w.r.t the distributions themselves can be made. +Additionally, we can calculate the TPR, FPR given the probability distributions CDF and ICDF functions. If we can gaurantee these functions to be differentiable, which proved to be the main challenge of this work, we can gaurantee the entire process to be differentiable. Once we do so, a derivative of the scores themselves w.r.t. the loss can be acheived. \subsection{General ROLL Formulation and Derivation} @@ -157,11 +158,11 @@ Let $\hat{F}_1$ and $\hat{F}_0$ denote the CDFs of $P_{\hat{\phi}_1}$ and $P_{\h respectively. Specific choices of $\mathcal{F}$ (Gaussian, Beta, KDE) are discussed in \Cref{sec:roll-instantiations}. -Using this notation, at a threshold $\alpha$: +Using this notation, at a threshold $\tau$: \begin{align} - \operatorname{TPR}(\alpha) &= 1 - \hat{F}_1(\alpha), \label{eq:tpr-cdf} \\ - \operatorname{FPR}(\alpha) &= \hat{F}_0(\alpha). \label{eq:fpr-cdf} -\end{align} + \operatorname{TPR}(\tau) &= 1 - \hat{F}_1(\tau), \label{eq:tpr-cdf} \\ + \operatorname{FPR}(\tau) &= 1 - \hat{F}_0(\tau). \label{eq:fpr-cdf} +\end{align}t Let $\hat{F}_1^{-1}$ and $\hat{F}_0^{-1}$ denote the quantile functions of $P_{\hat{\phi}_1}$ and $P_{\hat{\phi}_0}$, respectively. The threshold achieving a target TPR of $\alpha$ follows directly @@ -172,34 +173,35 @@ from \eqref{eq:tpr-cdf}: \] and similarly for a target FPR of $\alpha$, from \eqref{eq:fpr-cdf}: \[ - \operatorname{FPR}(\tau) = \alpha \;\Longrightarrow\; \hat{F}_0(\tau) = \alpha - \;\Longrightarrow\; \tau = \hat{F}_0^{-1}(\alpha) + \operatorname{FPR}(\tau) = \alpha \;\Longrightarrow\; 1 - \hat{F}_0(\tau) = \alpha + \;\Longrightarrow\; \tau = \hat{F}_0^{-1}(1 - \alpha) \] This yields two versions of our objective. Substituting the ICDF threshold into the rate -expressions, our estimated TPR at a fixed FPR of $\alpha$ is $1 - \hat{F}_1(\hat{F}_0^{-1}(\alpha))$. +expressions, our estimated TPR at a fixed FPR of $\alpha$ is $1 - \hat{F}_1(\hat{F}_0^{-1}(1-\alpha))$. Therefore, to maximise TPR we minimise: \begin{equation} - \mathcal{L}_{\text{ROLL-TPR@FPR}}(f_{\theta}(\mathcal{B}) ; \alpha) = \hat{F}_1(\hat{F}_0^{-1}(\alpha)) + \mathcal{L}_{\text{ROLL-TPR@FPR}}(f_{\theta}(\mathcal{B}) ; \alpha) = \hat{F}_1(\hat{F}_0^{-1}(1-\alpha)) \label{eq:roll-tpr-at-fpr} \end{equation} -Our estimated FPR at a fixed TPR of $\alpha$ is $\hat{F}_0(\hat{F}_1^{-1}(1 - \alpha))$. +Our estimated FPR at a fixed TPR of $\alpha$ is $1 - \hat{F}_0(\hat{F}_1^{-1}(1 - \alpha))$. Therefore, to minimise FPR: \begin{equation} - \mathcal{L}_{\text{ROLL-FPR@TPR}}(f_{\theta}(\mathbf{X}) ; \alpha) = \hat{F}_0(\hat{F}_1^{-1}(1 - \alpha)) + \mathcal{L}_{\text{ROLL-FPR@TPR}}(f_{\theta}(\mathbf{X}) ; \alpha) = 1 - \hat{F}_0(\hat{F}_1^{-1}(1 - \alpha)) \label{eq:roll-fpr-at-tpr} \end{equation} Observe that \eqref{eq:roll-tpr-at-fpr} and \eqref{eq:roll-fpr-at-tpr} share the same -functional structure: each evaluates one empirical CDF at the quantile of the other. This -symmetry means \eqref{eq:roll-fpr-at-tpr} can be reduced to \eqref{eq:roll-tpr-at-fpr} by -negating the model scores and exchanging the class labels. Concretely, replacing +inner structure: each evaluates one empirical CDF at the $(1-\alpha)$-quantile of the other. +The two objectives are interchangeable at the implementation level: replacing $f_\theta(\mathbf{x})$ with $-f_\theta(\mathbf{x})$ and $y$ with $1 - y$ swaps the roles -of the two populations, turning a TPR@FPR objective into a FPR@TPR one. Because the -two objectives are therefore interchangeable at the implementation level, all derivations +of the two populations, and passing target rate $1-\alpha$ to the resulting +TPR@FPR objective recovers the FPR@TPR objective at rate $\alpha$. Because +the two objectives are therefore interchangeable at the implementation level, all derivations and implementation details below are given for \eqref{eq:roll-tpr-at-fpr} only; -\eqref{eq:roll-fpr-at-tpr} follows by the same transformation applied to the inputs. +\eqref{eq:roll-fpr-at-tpr} follows by the same transformation applied to the inputs, with +the target rate complemented to $1-\alpha$. \Cref{fig:roll-principle} provides a geometric view of \eqref{eq:roll-tpr-at-fpr}. \begin{figure}[H] @@ -221,20 +223,20 @@ and implementation details below are given for \eqref{eq:roll-tpr-at-fpr} only; We now derive the gradient of \eqref{eq:roll-tpr-at-fpr} with respect to $f_\theta(\mathbf{x}_i)$. If $y_i = 1$, then $(\mathbf{x}_i, y_i) \in \mathcal{B}_1$ and $f_\theta(\mathbf{x}_i)$ has no -effect on $\hat{F}_0^{-1}(\alpha)$. Therefore: +effect on $\hat{F}_0^{-1}(1-\alpha)$. Therefore: \begin{equation} \left.\frac{\partial \mathcal{L}_{\text{ROLL-TPR@FPR}}(f_\theta(\mathcal{B}) ; \alpha)} {\partial f_\theta(\mathbf{x}_i)}\right|_{y_i = 1} - = \frac{\partial \hat{F}_1(\hat{F}_0^{-1}(\alpha))}{\partial f_\theta(\mathbf{x}_i)} + = \frac{\partial \hat{F}_1(\hat{F}_0^{-1}(1-\alpha))}{\partial f_\theta(\mathbf{x}_i)} \end{equation} If $y_i = 0$, then $(\mathbf{x}_i, y_i) \in \mathcal{B}_0$ and $f_\theta(\mathbf{x}_i)$ affects -$\hat{F}_0^{-1}(\alpha)$ instead. Applying the chain rule: +$\hat{F}_0^{-1}(1-\alpha)$ instead. Applying the chain rule: \begin{equation} \left.\frac{\partial \mathcal{L}_{\text{ROLL-TPR@FPR}}(f_\theta(\mathbf{X}) ; \alpha)} {\partial f_\theta(\mathbf{x}_i)}\right|_{y_i = 0} - = \frac{\partial \hat{F}_1(\hat{F}_0^{-1}(\alpha))}{\partial \hat{F}_0^{-1}(\alpha)} - \cdot \frac{\partial \hat{F}_0^{-1}(\alpha)}{\partial f_\theta(\mathbf{x}_i)} + = \frac{\partial \hat{F}_1(\hat{F}_0^{-1}(1-\alpha))}{\partial \hat{F}_0^{-1}(1-\alpha)} + \cdot \frac{\partial \hat{F}_0^{-1}(1-\alpha)}{\partial f_\theta(\mathbf{x}_i)} \end{equation} Unifying both cases, the general gradient applicable to all ROLL instantiations is: @@ -242,10 +244,10 @@ Unifying both cases, the general gradient applicable to all ROLL instantiations \frac{\partial \mathcal{L}_{\text{ROLL-TPR@FPR}}(f_\theta(\mathbf{X}) ; \alpha)} {\partial f_\theta(\mathbf{x}_i)} = \begin{cases} - \dfrac{\partial \hat{F}_1(\hat{F}_0^{-1}(\alpha))}{\partial f_\theta(\mathbf{x}_i)} + \dfrac{\partial \hat{F}_1(\hat{F}_0^{-1}(1-\alpha))}{\partial f_\theta(\mathbf{x}_i)} & \text{if } y_i = 1 \\[10pt] - \dfrac{\partial \hat{F}_1(\hat{F}_0^{-1}(\alpha))}{\partial \hat{F}_0^{-1}(\alpha)} - \cdot \dfrac{\partial \hat{F}_0^{-1}(\alpha)}{\partial f_\theta(\mathbf{x}_i)} + \dfrac{\partial \hat{F}_1(\hat{F}_0^{-1}(1-\alpha))}{\partial \hat{F}_0^{-1}(1-\alpha)} + \cdot \dfrac{\partial \hat{F}_0^{-1}(1-\alpha)}{\partial f_\theta(\mathbf{x}_i)} & \text{if } y_i = 0 \end{cases} \label{eq:roll-gradient} @@ -253,6 +255,49 @@ Unifying both cases, the general gradient applicable to all ROLL instantiations The concrete form of each partial derivative depends on the choice of distribution family $\mathcal{F}$, and is derived for each instantiation in \Cref{sec:roll-instantiations}. +\subsection{ROLL variant - direct AUC optimisation} + +In addition to optimising for a specific rate, ROLL provides us an opportunity to +optimize the AUC of the ROC directly. + +The AUC is defined as the area under the curve of the ROC. The ROC is a function that +for every FPR gives us the performing TPR of the model we have fitted. + +Formally, for the function $TPR(\alpha)$ as defined above, we may define AUC as: + +\begin{equation} + \operatorname{AUC} = \int_{0}^{1}\operatorname{TPR}(\alpha) d \alpha +\end{equation} + +The AUC is something we would like to maximize. In order to do so, we would like to +minimize the area over the curve, which is $1-AUC$. + +We note that $1-\operatorname{TPR}(\alpha) = \mathcal{L}(TPR@FPR)$. + +From here, we would like to minimize: + +\begin{equation} + \mathcal{L}_{AOC} = \int_0^1\mathcal{L}_{\text{ROLL-TPR@FPR}}(\alpha) d \alpha +\end{equation} + +A direct integration is not part of this work. However, integration can be approximated. Instead +of integrating directly, it is possible to evaluate the loss for every FPR between 0 and 1, sum them, and re-normalize. + +Therefor, subdividing the interval $(0, 1)$ to 99 steps (every alpha starting from $0.01$ and ending with $0.99$, since a value of $0$ or $1$ would be illegal), our loss for minimizing AOC becomes: + +\begin{equation} + \mathcal{L}_{ROLL-AOC} = \frac{1}{99}\sum_{i=1}^{99}\mathcal{L}_{ROLL-TPR@FPR}\left(\frac{i}{100}\right) + \label{eq:roll-aoc} +\end{equation} + +The gradient per score then simply becomes the average gradient over every threshold. + +\begin{equation} + \frac{\partial \mathcal{L}_{ROLL-AOC}(f_\theta(\mathbf{X}))} + {\partial f_\theta(\mathbf{x}_i)} = \frac{1}{99}\sum_{i=1}^{99}\left(\frac{\partial \mathcal{L}_{\text{ROLL-TPR@FPR}}\left(f_\theta(\mathbf{X}) ; \frac{i}{100}\right)} + {\partial f_\theta(\mathbf{x}_i)} \right) + \label{eq:roll-aoc-gradient} +\end{equation} %------------------------------------------------ @@ -322,7 +367,7 @@ available in standard numerical libraries (e.g.\ \texttt{torch.erf} and \texttt{torch.erfinv}). Plugging into the general ROLL framework, the threshold $\tau$ achieving FPR $= \alpha$ and the resulting loss are: \begin{align} - \tau &= \mu_0 + \sigma_0\sqrt{2}\,\text{ierf}(2\alpha - 1) \nonumber \\ + \tau &= \mu_0 + \sigma_0\sqrt{2}\,\text{ierf}(1 - 2\alpha) \nonumber \\ \mathcal{L}_{\text{ROLL-TPR@FPR}}^{\text{GAUSSIAN}}(f_{\theta}(\mathcal{B}) ; \alpha) &= \frac{1}{2}\left[1 + \text{erf}\!\left(\frac{\tau - \mu_1}{\sigma_1\sqrt{2}}\right)\right] \label{eq:roll-tpr-at-fpr-gaussian} @@ -331,87 +376,8 @@ $\tau$ achieving FPR $= \alpha$ and the resulting loss are: \subsubsection{Gradient Derivation} \label{sec:roll-gaussian-backward} -% Differentiate the Gaussian loss with respect to $f_\theta(\mathbf{x}_i)$. -% Gradients flow through $\mu_k$ and $\sigma_k^2$ (which are differentiable -% functions of the scores), and through $\Phi$ and $\Phi^{-1}$, which have -% simple closed-form derivatives. - -In order to compute the gradient derivation for the gaussian estimates we must first compute the gradient to each of the parameters. -Firstly, for $y_i = 1$. - -\[ - \dfrac{\partial \hat{F}_1(\hat{F}_0^{-1}(\alpha))}{\partial \mu_1} = - \frac{\partial \frac{1}{2}\left[1 + \text{erf}\!\left(\frac{\hat{F}_0^{-1}(\alpha) - \mu_1}{\sigma_1\sqrt{2}}\right)\right]}{\partial \mu_1} -\] - -\[ - = -\frac{1}{\sigma_1\sqrt{2\pi}}\exp\!\left(-\frac{(\hat{F}_0^{-1}(\alpha) - \mu_1)^2}{2\sigma_1^2}\right) -\] - -\[ - \frac{\partial \mu_1}{\partial f_{\theta}(\mathbf{x}_i)} = \frac{1}{|\mathcal{B}_1|} -\] - -\[ - \dfrac{\partial \hat{F}_1(\hat{F}_0^{-1}(\alpha))}{\partial \sigma_1} = - \frac{\partial \frac{1}{2}\left[1 + \text{erf}\!\left(\frac{\hat{F}_0^{-1}(\alpha) - \mu_1}{\sigma_1\sqrt{2}}\right)\right]}{\partial \sigma_1} -\] - -\[ - = \frac{\mu_1 - \hat{F}_0^{-1}(\alpha)}{\sigma_1^2\sqrt{2\pi}} \exp\!\left( -\frac{(\hat{F}_0^{-1}(\alpha) - \mu_1)^2}{2\sigma_1^2} \right) -\] -\[ - \frac{\partial \sigma_1}{\partial f_{\theta}(\mathbf{x}_i)} = \frac{f_\theta(\mathbf{x}_i) - \mu_1}{|\mathcal{B}_1| \sigma_1} -\] - -Combining via the chain rule, the gradient for $y_i = 1$ is: -\begin{equation} - \dfrac{\partial \hat{F}_1(\hat{F}_0^{-1}(\alpha))}{\partial f_{\theta}(\mathbf{x}_i)} - = -\frac{1}{|\mathcal{B}_1|\,\sigma_1\sqrt{2\pi}} - \exp\!\left(-\frac{(\tau - \mu_1)^2}{2\sigma_1^2}\right) - \left(1 + \frac{(\tau - \mu_1)(f_\theta(\mathbf{x}_i) - \mu_1)}{\sigma_1^2}\right) - \label{eq:gauss-grad-y1} -\end{equation} -where $\tau = \hat{F}_0^{-1}(\alpha) = \mu_0 + \sigma_0\sqrt{2}\,\operatorname{ierf}(2\alpha - 1)$. - -Given $y_i = 0$, the score $f_\theta(\mathbf{x}_i)$ affects the loss only through the threshold -$\tau = \hat{F}_0^{-1}(\alpha)$, which depends on $\mu_0$ and $\sigma_0$. -Applying the chain rule: -\[ - \frac{\partial \hat{F}_1(\tau)}{\partial f_\theta(\mathbf{x}_i)} - = \underbrace{\frac{\partial \hat{F}_1(\tau)}{\partial \tau}}_{\text{PDF of class 1 at }\tau} - \cdot \frac{\partial \tau}{\partial f_\theta(\mathbf{x}_i)} -\] - -The first factor is the Gaussian PDF evaluated at $\tau$: -\[ - \frac{\partial \hat{F}_1(\tau)}{\partial \tau} - = \frac{1}{\sigma_1\sqrt{2\pi}}\exp\!\left(-\frac{(\tau - \mu_1)^2}{2\sigma_1^2}\right) -\] - -For the second factor, $\tau = \mu_0 + \sigma_0\sqrt{2}\,\operatorname{ierf}(2\alpha - 1)$, so -$\frac{\partial \tau}{\partial \mu_0} = 1$ and -$\frac{\partial \tau}{\partial \sigma_0} = \sqrt{2}\,\operatorname{ierf}(2\alpha - 1) = \frac{\tau - \mu_0}{\sigma_0}$. -Combined with $\frac{\partial \mu_0}{\partial f_\theta(\mathbf{x}_i)} = \frac{1}{|\mathcal{B}_0|}$ and -$\frac{\partial \sigma_0}{\partial f_\theta(\mathbf{x}_i)} = \frac{f_\theta(\mathbf{x}_i) - \mu_0}{|\mathcal{B}_0|\sigma_0}$: -\[ - \frac{\partial \tau}{\partial f_\theta(\mathbf{x}_i)} - = \frac{1}{|\mathcal{B}_0|}\left(1 + \frac{(\tau - \mu_0)(f_\theta(\mathbf{x}_i) - \mu_0)}{\sigma_0^2}\right) -\] - -Therefore, the gradient for $y_i = 0$ is: -\begin{equation} - \dfrac{\partial \hat{F}_1(\hat{F}_0^{-1}(\alpha))}{\partial f_\theta(\mathbf{x}_i)} - = \frac{1}{|\mathcal{B}_0|\,\sigma_1\sqrt{2\pi}} - \exp\!\left(-\frac{(\tau - \mu_1)^2}{2\sigma_1^2}\right) - \left(1 + \frac{(\tau - \mu_0)(f_\theta(\mathbf{x}_i) - \mu_0)}{\sigma_0^2}\right) - \label{eq:gauss-grad-y0} -\end{equation} - -\paragraph{Combined gradient.} - -Substituting \Cref{eq:gauss-grad-y1} and \Cref{eq:gauss-grad-y0} into \Cref{eq:roll-gradient}, -and letting $\tau = \hat{F}_0^{-1}(\alpha) = \mu_0 + \sigma_0\sqrt{2}\,\operatorname{ierf}(2\alpha-1)$: +The full derivation is given in Appendix~\ref{appendix:gauss-grad}. +Letting $\tau = \hat{F}_0^{-1}(1-\alpha) = \mu_0 + \sigma_0\sqrt{2}\,\operatorname{ierf}(1-2\alpha)$, the gradient is: \begin{equation} \frac{\partial \mathcal{L}_{\text{ROLL-TPR@FPR}}^{\text{GAUSSIAN}}}{\partial f_\theta(\mathbf{x}_i)} = @@ -476,10 +442,10 @@ Substituting into the general ROLL framework \eqref{eq:roll-tpr-at-fpr}: \mathcal{L}_{\text{ROLL-TPR@FPR}}^{\text{BETA}}(f_\theta(\mathcal{B});\,\alpha) = I_{\hat\tau}(\hat{a}_1,\hat{b}_1), \qquad - \hat\tau = I^{-1}_\alpha(\hat{a}_0,\hat{b}_0) + \hat\tau = I^{-1}_{1-\alpha}(\hat{a}_0,\hat{b}_0) \label{eq:roll-tpr-at-fpr-beta} \end{equation} -where $I^{-1}_\alpha(a,b)$ denotes the $\alpha$-quantile of $\operatorname{Beta}(a,b)$. +where $I^{-1}_{1-\alpha}(a,b)$ denotes the $(1-\alpha)$-quantile of $\operatorname{Beta}(a,b)$. \subsubsection{Gradient Derivation} \label{sec:roll-beta-backward} @@ -492,12 +458,6 @@ Gradients of \eqref{eq:roll-tpr-at-fpr-beta} with respect to $f_\theta(\mathbf{x are therefore propagated via automatic differentiation through the estimator \eqref{eq:beta-params}, the CDF evaluation, and the quantile inversion. -Note that the gradient balance property (\Cref{prop:gradient-balance}) does not hold -for Beta ROLL: the sigmoid activation that maps raw scores into $(0,1)$ is nonlinear, -so a uniform additive shift of the raw scores produces a non-uniform shift of the -transformed inputs, violating the translation-invariance assumption required by the -proof. - \subsection{KDE ROLL} \label{sec:roll-kde} @@ -522,7 +482,7 @@ As before, to calculate the loss, we calculate: \[ - \mathcal{L}_{\text{ROLL-TPR@FPR}}^{\text{KDE}}(f_{\theta}(\mathcal{B}) ; \alpha) = \hat{F}_1(\hat{F}_0^{-1}(\alpha)) + \mathcal{L}_{\text{ROLL-TPR@FPR}}^{\text{KDE}}(f_{\theta}(\mathcal{B}) ; \alpha) = \hat{F}_1(\hat{F}_0^{-1}(1-\alpha)) \] To calculate this, we first define the kernel function as $\sigma '$, and the CDF of the kernel function as $\sigma$. The approach used here is to define $\sigma$ as a sigmoid function,. @@ -542,24 +502,10 @@ The CDF of the KDE function then becomes: \hat{F}_{KDE}(\tau ; \mathbf{X}) = \frac{1}{|X|}\sum_i \sigma(\tau - x_i) \] -While the CDF has a nice formula, the inverse CDF has no known closed formula. It instead must be calculated numerically. Thus, the calculation of the decision threshold $\tau$ must be achevied -using a numerical calculation algorithm. In this work, the Newton--Raphson method~\cite{press2007numerical} is chosen. - -Firstly we must calculate $\hat{F}_0^{-1}(\alpha)$ = \tau. We start with our initial guess, $\tau_0$, and for each step, calculate: - -\[ - \tau_{n+1} = \tau_n - \frac{\hat{F}_0(\tau_n ; \mathcal{X}_0) - \alpha}{\frac{\partial \hat{F}_0(\tau_n ; \mathcal{X}_0)}{\partial \tau}} -\] - -This step is taken until $\hat{F}_0(\tau_n ; \mathcal{B}_0) \approx \alpha$ within some acceptable error (in our case $1e-4$). - -Our derivative w.r.t. $\tau$ is - -\[ % - \frac{\partial \hat{F}_0(\tau_n ; \mathcal{X}_0)}{\partial \tau} = \frac{1}{|\mathcal{X}_0|}\sum_i \sigma'(\tau - x_i) -\] - -At this point, we have succesfully calculated $\tau$ for which $\tau = \hat{F}_0^{-1}(\alpha ; \mathbf{X}_0)$. +While the CDF has a closed form, its inverse has none and must be found numerically. +We use bisection, which requires no derivative evaluation and is guaranteed to converge +for any strictly monotone CDF; the bracket construction and iteration are detailed in +Appendix~\ref{appendix:kde-bisection}. We can now relatively easily calculate $\hat{F}_1(\tau ; \mathbf{X}_1)$ using the formulat for $\hat{F}_{KDE}(\tau ; \mathbf{X})$ above. @@ -574,144 +520,7 @@ Importantly, we must save the calculation of $\tau$ for the backward derivation, % Gradients flow through the kernel evaluations back to the model scores. % This is the section that connects to \Cref{sec:roll-backward} motivation. -We derive the concrete form of the two terms from \Cref{eq:roll-gradient} for the KDE instantiation, -where $\tau = \hat{F}_0^{-1}(\alpha ; \mathcal{B}_0)$. - -\paragraph{Case $y_i = 1$ (positive class).} - -When $\mathbf{x}_i \in \mathcal{B}_1$, the score $f_\theta(\mathbf{x}_i)$ appears directly in $\hat{F}_1$ -and has no effect on $\tau$ (which depends only on $\mathcal{B}_0$). Therefore: - -\[ - \dfrac{\partial \hat{F}_1(\hat{F}_0^{-1}(\alpha))}{\partial f_{\theta}(\mathbf{x}_i)} = - \frac{\partial \frac{1}{|\mathcal{B}_1|}\sum_{\mathbf{x}_j \in \mathcal{B}_1} \sigma_1(\tau - f_{\theta}(\mathbf{x}_j))}{\partial f_{\theta}(\mathbf{x}_i)} -\] - -\[ - = \frac{\partial \left(\sum_{\mathbf{x}_j \in \mathcal{B}_1 ; j \neq i} \frac{1}{|\mathcal{B}_1|}\sigma_1(\tau - f_{\theta}(\mathbf{x}_j)) + \frac{1}{|\mathcal{B}_1|}\sigma_1(\tau - f_{\theta}(\mathbf{x}_i))\right)}{\partial f_{\theta}(\mathbf{x}_i)} -\] - -Applying the chain rule to the only $f_\theta(\mathbf{x}_i)$-dependent term, -$\frac{\partial}{\partial f_\theta(\mathbf{x}_i)}(\tau - f_\theta(\mathbf{x}_i)) = -1$: - -\begin{equation} - \frac{\partial \hat{F}_1(\hat{F}_0^{-1}(\alpha))}{\partial f_{\theta}(\mathbf{x}_i)} = -\frac{1}{|\mathcal{B}_1|}\sigma_1'(\tau - f_{\theta}(\mathbf{x}_i)) - \label{eq:kde-grad-y1} -\end{equation} - -\paragraph{Case $y_i = 0$ (negative class).} - -When $\mathbf{x}_i \in \mathcal{B}_0$, the score $f_\theta(\mathbf{x}_i)$ does not appear directly in -$\hat{F}_1$, but influences it through the threshold $\tau$. Per \Cref{eq:roll-gradient}, we compute -each factor of the chain rule separately. - -\medskip\noindent\textit{Derivative of $\hat{F}_1$ with respect to $\tau$.} - -\[ - \frac{\partial \hat{F}_1(\hat{F}_0^{-1}(\alpha))}{\partial \hat{F}_0^{-1}(\alpha)} = \frac{\partial \frac{1}{|\mathcal{B}_1|}\sum_{\mathbf{x}_j \in \mathcal{B}_1} \sigma_1(\tau - f_{\theta}(\mathbf{x}_j))}{\partial \tau} -\] - -Applying the chain rule, $\frac{\partial}{\partial\tau}(\tau - f_\theta(\mathbf{x}_j)) = +1$: - -\begin{equation} - = +\frac{1}{|\mathcal{B}_1|}\sum_{\mathbf{x}_j \in \mathcal{B}_1}\sigma_1'(\tau - f_{\theta}(\mathbf{x}_j)) - \label{eq:kde-dF1-dtau} -\end{equation} - -\medskip\noindent\textit{Derivative of $\tau$ with respect to $f_\theta(\mathbf{x}_i)$.} - -This requires differentiating a quantity computed numerically --- $\tau = \hat{F}_0^{-1}(\alpha ; \mathcal{B}_0)$ -is found via Newton's method rather than in closed form. - -We apply the inverse derivative rule: - -\[ - f'(x) = \frac{1}{f^{-1}'(f(x))} -\] - -This allows us to use the derivative of the inverse function instead. We need the inverse of -$\hat{F}_0^{-1}$ viewed as a function of $f_\theta(\mathbf{x}_i)$ --- that is, an expression for -$f_\theta(\mathbf{x}_i)$ in terms of $\tau$, $\alpha$, and $\mathcal{B}_0 \setminus \{\mathbf{x}_i\}$. -Solving $|\mathcal{B}_0|\cdot\alpha = \sum_{\mathbf{x}_j \in \mathcal{B}_0}\sigma_0(\tau - f_\theta(\mathbf{x}_j))$ -for $f_\theta(\mathbf{x}_i)$ gives: - -\[ - f_\theta(\mathbf{x}_i) = \tau - \sigma_0^{-1}\left( |\mathcal{B}_0|\cdot\alpha - \sum_{\mathbf{x}_j \in \mathcal{B}_0 ; j \neq i}\sigma_0(\tau - f_{\theta}(\mathbf{x}_j))\right) -\] - -Applying the inverse derivative rule to this inverse: - -\[ - \frac{\partial \hat{F}_0^{-1}(\alpha ; \mathcal{B}_0)}{\partial f_\theta(\mathbf{x}_i)} = \frac{1}{\frac{\partial \left(\tau - \sigma_0^{-1}\left( |\mathcal{B}_0|\cdot \alpha - \sum_{\mathbf{x}_j \in \mathcal{B}_0 ; j \neq i}\sigma_0(\tau - f_{\theta}(\mathbf{x}_j))\right)\right)}{\partial \tau}} -\] - -Applying the chain rule: - -\[ - = \frac{1}{\sigma_0^{-1}{}'\left( |\mathcal{B}_0|\cdot \alpha - \sum_{\mathbf{x}_j \in \mathcal{B}_0 ; j \neq i}\sigma_0(\tau - f_{\theta}(\mathbf{x}_j))\right)\cdot\left( \sum_{\mathbf{x}_j \in \mathcal{B}_0 ; j \neq i}\sigma_0'(\tau - f_{\theta}(\mathbf{x}_j))\right) + 1} -\] - -Since $|\mathcal{B}_0|\cdot\alpha = \sum_{\mathbf{x}_j \in \mathcal{B}_0}\sigma_0(\tau - f_\theta(\mathbf{x}_j))$, -the argument of $\sigma_0^{-1}{}'$ simplifies: - -\[ - |\mathcal{B}_0|\cdot \alpha - \sum_{\mathbf{x}_j \in \mathcal{B}_0 ; j \neq i}\sigma_0(\tau - f_{\theta}(\mathbf{x}_j)) = \sigma_0(\tau - f_{\theta}(\mathbf{x}_i)) -\] - -Therefore: - -\[ - \frac{\partial \hat{F}_0^{-1}(\alpha ; \mathcal{B}_0)}{\partial f_\theta(\mathbf{x}_i)} = \frac{1}{\sigma_0^{-1}{}'\!\left( \sigma_0(\tau - f_{\theta}(\mathbf{x}_i)) \right)\cdot\left( \sum_{\mathbf{x}_j \in \mathcal{B}_0 ; j \neq i}\sigma_0'(\tau - f_{\theta}(\mathbf{x}_j))\right) + 1 } -\] - -Substituting $\sigma_0^{-1}{}'(\sigma_0(u)) = \frac{1}{\sigma_0'(u)}$ and multiplying numerator and denominator -by $\sigma_0'(\tau - f_{\theta}(\mathbf{x}_i))$: - -\begin{equation} - \frac{\partial \hat{F}_0^{-1}(\alpha ; \mathcal{B}_0)}{\partial f_\theta(\mathbf{x}_i)} = - \frac{\sigma_0'(\tau - f_{\theta}(\mathbf{x}_i))}{\displaystyle\sum_{\mathbf{x}_j \in \mathcal{B}_0}\sigma_0'(\tau - f_{\theta}(\mathbf{x}_j))} - \label{eq:kde-grad-tau} -\end{equation} - -\medskip\noindent\textit{Efficient computation via the sigmoid identity.} - -Direct evaluation of \eqref{eq:kde-grad-tau} requires computing $\sigma_0'$ for every -point, then dividing by the per-point value — potentially unstable when a point is far -from $\tau$. For the sigmoid kernel, we can avoid this by exploiting the identity - -\begin{equation} - \sigma(u;\,v)\,\bigl(1 - \sigma(u;\,v)\bigr) = \frac{\sigma'(u;\,v)}{v} - \label{eq:sigmoid-identity} -\end{equation} - -which holds for all $u \in \mathbb{R}$ (proved by direct substitution: both sides equal -$\exp(-v|u|)/(1+\exp(-v|u|))^2$). Applying this with $u = \tau - f_\theta(\mathbf{x}_j)$: - -\[ - \sigma_0'(\tau - f_\theta(\mathbf{x}_j)) = v_0\,\sigma_0(\tau - f_\theta(\mathbf{x}_j)) - \,\bigl(1-\sigma_0(\tau - f_\theta(\mathbf{x}_j))\bigr) -\] - -Since $v_0$ cancels between numerator and denominator of \eqref{eq:kde-grad-tau}, -the ratio can be written entirely in terms of the sigmoid values already computed -during the forward pass: - -\begin{equation} - \frac{\partial \hat{F}_0^{-1}(\alpha ; \mathcal{B}_0)}{\partial f_\theta(\mathbf{x}_i)} - = - \frac{\sigma_0(\tau-f_\theta(\mathbf{x}_i))\,\bigl(1-\sigma_0(\tau-f_\theta(\mathbf{x}_i))\bigr)} - {\displaystyle\sum_{\mathbf{x}_j \in \mathcal{B}_0} - \sigma_0(\tau-f_\theta(\mathbf{x}_j))\,\bigl(1-\sigma_0(\tau-f_\theta(\mathbf{x}_j))\bigr)} - \label{eq:kde-grad-tau-efficient} -\end{equation} - -This avoids recomputing $\sigma_0'$ (which requires an extra exponential), instead -reusing the sigmoid activations cached from the CDF computation. - -\paragraph{Combined gradient.} - -Substituting \Cref{eq:kde-grad-y1}, \Cref{eq:kde-dF1-dtau}, and \Cref{eq:kde-grad-tau} -into \Cref{eq:roll-gradient}: +The derivation is given in Appendix~\ref{appendix:kde-grad}; letting $\tau = \hat{F}_0^{-1}(1-\alpha ; \mathcal{B}_0)$, the gradient is: \begin{equation} \frac{\partial \mathcal{L}_{\text{ROLL-TPR@FPR}}}{\partial f_\theta(\mathbf{x}_i)} = @@ -726,87 +535,10 @@ into \Cref{eq:roll-gradient}: \label{eq:kde-grad-combined} \end{equation} -where $\tau = \hat{F}_0^{-1}(\alpha ; \mathcal{B}_0)$. +where $\tau = \hat{F}_0^{-1}(1-\alpha ; \mathcal{B}_0)$. -\subsubsection{Sigmoid Kernel: Explicit Equations} -\label{sec:roll-kde-sigmoid} - -The derivations above hold for any differentiable CDF kernel $\sigma$. -In our implementation we choose the logistic sigmoid: -% -\begin{equation} - \sigma(x ; v) = \frac{1}{1 + \exp(-vx)}, - \qquad - \sigma'(x ; v) = \frac{v\,\exp(-v|x|)}{\bigl(1 + \exp(-v|x|)\bigr)^{2}} - \label{eq:sigmoid-kernel} -\end{equation} -% -where $v > 0$ is the bandwidth parameter. The derivative formula evaluates at -$|x|$ rather than $x$: since $\sigma'$ is an even function -($\sigma'(x) = \sigma'(-x)$ for any symmetric logistic), both forms are -mathematically identical, but $\exp(-v|x|) \to 0$ as $|x| \to \infty$ while -$\exp(-vx) \to \infty$ for $x \to -\infty$, so the $|x|$ form avoids -floating-point overflow when scores fall well below the threshold. - -\paragraph{Forward pass.} - -Substituting \eqref{eq:sigmoid-kernel} into the KDE CDF: -% -\begin{equation} - \hat{F}_{k}(\tau ; \mathbf{s}^{(k)}) = - \frac{1}{|\mathcal{B}_k|} - \sum_{\mathbf{x}_j \in \mathcal{B}_k} - \frac{1}{1 + \exp\!\bigl(-v_k\bigl(\tau - f_\theta(\mathbf{x}_j)\bigr)\bigr)} - \label{eq:kde-sigmoid-cdf} -\end{equation} -% -and its derivative with respect to $\tau$ — used both in the Newton--Raphson -inversion and in the gradient computation below — is: -% -\begin{equation} - \frac{\partial \hat{F}_{k}(\tau)}{\partial \tau} - = - \frac{1}{|\mathcal{B}_k|} - \sum_{\mathbf{x}_j \in \mathcal{B}_k} - \frac{v_k\,\exp\!\bigl(-v_k\bigl|\tau - f_\theta(\mathbf{x}_j)\bigr|\bigr)} - {\Bigl(1 + \exp\!\bigl(-v_k\bigl|\tau - f_\theta(\mathbf{x}_j)\bigr|\bigr)\Bigr)^{2}} - \label{eq:kde-sigmoid-pdf} -\end{equation} - -\paragraph{Gradient.} - -Define the sigmoid kernel PDF shorthand: -\begin{equation} - \varphi_k(u) \;=\; - \frac{v_k\,\exp(-v_k|u|)}{\bigl(1+\exp(-v_k|u|)\bigr)^{2}} - \label{eq:sigmoid-phi} -\end{equation} -This is simply $\sigma'(u ; v_k)$ from \eqref{eq:sigmoid-kernel}, a bell-shaped function -centred at zero with width controlled by bandwidth $v_k$. -Substituting \eqref{eq:sigmoid-kernel} into \eqref{eq:kde-grad-combined} and using this -notation, the explicit sigmoid-kernel gradient is: - -\begin{equation} - \frac{\partial \mathcal{L}_{\text{ROLL-TPR@FPR}}}{\partial f_\theta(\mathbf{x}_i)} = - \begin{cases} - -\dfrac{\varphi_1\!\left(\tau - f_\theta(\mathbf{x}_i)\right)}{|\mathcal{B}_1|} - & \text{if } y_i = 1\\[14pt] - +\,\dfrac{\displaystyle\sum_{\mathbf{x}_j \in \mathcal{B}_1} - \varphi_1\!\left(\tau - f_\theta(\mathbf{x}_j)\right)}{|\mathcal{B}_1|} - \;\cdot\; - \dfrac{\varphi_0\!\left(\tau-f_\theta(\mathbf{x}_i)\right)} - {\displaystyle\sum_{\mathbf{x}_j \in \mathcal{B}_0} - \varphi_0\!\left(\tau-f_\theta(\mathbf{x}_j)\right)} - & \text{if } y_i = 0 - \end{cases} - \label{eq:kde-sigmoid-grad} -\end{equation} - -where $\tau = \hat{F}_0^{-1}(\alpha ; \mathcal{B}_0)$. -The signs reflect the direction of each class's effect on the loss: raising a -positive-class score pushes $\hat{F}_1(\tau)$ down (gradient negative), while -raising a negative-class score shifts $\tau$ right, also lowering $\hat{F}_1(\tau)$ -(gradient positive). Positive-class samples are weighted by their individual kernel +The explicit sigmoid-kernel form of \eqref{eq:kde-grad-combined} — forward pass CDF, efficient gradient, and implementation notes — is given in Appendix~\ref{appendix:kde-sigmoid}. +Positive-class samples are weighted by their individual kernel PDF at $\tau$; negative-class samples are weighted by the mean positive-class kernel PDF scaled by each sample's share of the negative-class kernel mass. @@ -859,7 +591,7 @@ From \Cref{eq:roll-gradient}, for $y_i = 0$: We claim $\sum_{\mathbf{x}_i \in \mathcal{B}_0}\frac{\partial \tau}{\partial f_\theta(\mathbf{x}_i)} = 1$. Shift all negative scores uniformly: $f_\theta(\mathbf{x}_i) \to f_\theta(\mathbf{x}_i) + \delta$ for $\mathbf{x}_i \in \mathcal{B}_0$. By translation invariance, $\hat{F}_0$ simply translates, so -$\tau = \hat{F}_0^{-1}(\alpha)$ shifts by exactly $\delta$. Differentiating with respect to $\delta$ at +$\tau = \hat{F}_0^{-1}(1-\alpha)$ shifts by exactly $\delta$. Differentiating with respect to $\delta$ at $\delta = 0$: \[ 1 = \frac{\mathrm{d}\tau}{\mathrm{d}\delta}\bigg|_{\delta=0} @@ -887,25 +619,25 @@ Differentiating at $\delta = 0$: Combining with \eqref{eq:grad-balance-b0} gives \eqref{eq:grad-balance}. \end{proof} -The translation-invariance assumption holds for all distribution families considered in this -work: for Gaussian MLE, a uniform shift in scores moves $\mu_k$ by the same amount while +The translation-invariance assumption holds for both the Gaussian distribution, +as well as the KDE-based distribution, but not for the Beta distribution. +For Gaussian MLE, a uniform shift in scores moves $\mu_k$ by the same amount while leaving $\sigma_k$ unchanged, which translates $\hat{F}_k$; for KDE, each kernel term is evaluated at $\tau - f_\theta(\mathbf{x}_j)$, so a uniform shift in the $f_\theta(\mathbf{x}_j)$ is equivalent to an equal shift in $\tau$. The condition is necessary: without it, a uniform score shift need not produce a rigid translation of $\hat{F}_k$, so the shift argument in the -proof breaks down and the gradient sums need not be equal. A natural example where this fails -is a family that first maps scores through a nonlinear link function before fitting, such as -passing scores through a sigmoid into $[0,1]$ before fitting a Beta distribution. A uniform -additive shift of the raw scores then produces a non-uniform shift of the transformed inputs, -changing the shape of the fitted distribution rather than merely translating it, and the -balance property no longer holds. +proof breaks down and the gradient sums need not be equal. + +The Beta distribution only accepts values in the interval $\[0, 1\]$. Since it +is mapped only over an interval, the translation-invariance assumption does not hold +for this distribution. \paragraph{Gradient locality.} \label{para:gradient-locality} -A second structural consequence of the ROLL formulation is that gradient mass is +A second structural consequence of the ROLL-KDE formulation is that gradient mass is \emph{concentrated near the operating threshold $\tau$}. Samples whose scores lie -close to $\tau$ receive disproportionately large gradient updates, while samples +close to $\tau$ receive larger gradient updates, while samples already far on the correct side contribute very little. This follows directly from \Cref{eq:kde-grad-combined}. For the positive class ($y_i = 1$), @@ -922,15 +654,14 @@ again bell-shaped and centred on $\tau$. The effect is that each gradient step focuses the model's attention on the region that directly determines the operating-point performance: samples that could plausibly be -re-ranked relative to the threshold at the current step. Samples comfortably classified -on the correct side contribute negligible signal, not because they are deemed unimportant, -but because their contribution to the CDF estimate at $\tau$ is already saturated. +re-ranked relative to the threshold at the current step. Samples classified with strong +confidence relative to the threshold, with scores far enough away from said threshold, +receive small gradient updates, since a small change to the score of these samples will not +bring any change to the placement of the threshold itself, or the performance at said threshold. This stands in contrast to standard losses such as cross-entropy, where the per-sample gradient is determined by the predicted probability, with no direct dependence on an -operating threshold. Under heavy class imbalance this can cause the dominant class to -``push'' the threshold away from the intended operating point, a problem that gradient -locality avoids by construction. +operating threshold. \begin{observation}[Gradient locality] \label{obs:gradient-locality} @@ -958,32 +689,34 @@ concentration of gradient mass around $\tau$, with smooth decay on either side. \label{fig:threshold-locality} \end{figure} - -\subsection{Gradient Computation and the Custom Backward Pass} -\label{sec:roll-backward} - -% Because the distribution parameters are themselves functions of model scores -% (not fixed), the backward pass must differentiate through the distribution -% fitting step. Describe the custom autograd implementation: how gradients flow -% from the ROLL loss back through the distribution parameters to the model -% weights. Highlight where standard autograd would fail and what the manual -% backward pass does differently. - %------------------------------------------------ \section{Implementation Considerations} \label{sec:roll-implementation} -\subsection{Numerical Stability and the Scaling Trick} +\subsection{Combatting Numerical Instability With Score Scaling} \label{sec:roll-numerical-stability} -% The KDE loss involves sums of kernel evaluations that can span many orders of -% magnitude, leading to floating-point underflow or overflow during training. -% Describe the scaling trick that normalizes these sums to a numerically stable -% range without changing the gradient direction, and show that it is equivalent -% to computing in log-space with a max-subtraction stabilizer (analogous to the -% log-sum-exp trick). +Before computing the KDE, all batch scores are divided by their overall standard +deviation: +\[ + \tilde{s}_i = \frac{f_\theta(\mathbf{x}_i)}{\hat\sigma_{\mathcal{B}}}, + \qquad + \hat\sigma_{\mathcal{B}} = \sqrt{\operatorname{Var}(f_\theta(\mathbf{x}_i) : (\mathbf{x}_i, y_i) \in \mathcal{B})}. +\] +This keeps the values given to the sigmoid kernel ($v(\tau - \tilde{s}_j)$) +near unit scale, preventing floating-point overflow and underflow in the exponential +evaluations. +The scaling has no effect on the loss value itself or derived gradients. +Silverman's rule derives the bandwidth proportionally to the data standard deviation, +$h \propto \hat\sigma \cdot n^{-1/5}$, so dividing all scores by $\hat\sigma_\mathcal{B}$ +causes the bandwidth to scale by the same factor. +The product $v \cdot (\tau - s_j)$ — the only quantity entering the sigmoid — is +therefore invariant under the rescaling. +In the backward pass, gradients with respect to the normalised scores are multiplied +by $1/\hat\sigma_\mathcal{B}$ to apply the chain rule, providing gradients mathematically +identical to those that would have been obtained without normalisation. \subsection{Bandwidth Estimation for KDE} \label{sec:kde-bandwidth} @@ -996,17 +729,33 @@ concentration of gradient mass around $\tau$, with smooth decay on either side. % NOTE - not silverman's rule, we do use scheduling, but we also use different % estimator - see impl. -When computing KDE, kernel selection and bandwidth estimation affect the final result greatly. Large bandwidths -don't accurately track the probability distribution, while small kernels result in a very jagged CDF, which for us means very low gradient values unless unless a point is very close to the decision threshold. +When computing KDE, bandwidth estimation strongly affects the result. Large bandwidths +produce an overly smooth CDF that fails to track the true score distribution; small +bandwidths produce a jagged CDF, yielding negligible gradients for all but the +nearest-threshold samples. -Use of the Improved Sheather-Jones (ISJ) method~\cite{botev2010kde} of bandwidth selection worked reliably well at creating very close-tracking, yet smooth CDFs. +We estimate the bandwidth using the Improved Sheather-Jones (ISJ) +method~\cite{botev2010kde}, which minimises the asymptotic mean integrated squared +error via an iterative plug-in procedure. ISJ tracks the true score distribution more +closely than closed-form rules, as illustrated in \Cref{fig:density-fit-comparison}. +Because ISJ is iterative, it can fail to converge on small or degenerate batches early +in training. In those cases we fall back to Silverman's rule of +thumb~\cite{silverman1986density}, +\[ + h = 1.06\,\hat{\sigma}\,n^{-1/5}, +\] +which is closed-form and always produces a valid bandwidth. +The kernel parameter is then set to $v = 1/h$. \subsubsection{Bandwidth Scaling for KDE} \label{sec:kde-bandwidth-scaling} -While the ISJ method worked very well for selecting an acceptable bandwidth, this wasn't necessarily wanted during training. Near the start of the training session, scores tended to be all low. This naturally made the selected bandwidth to be too low. This caused very low training performance near the start of a training session, which could result in non-convergence of the model even after significant training epochs elapsed. +Although we may select a valid bandwidth at each step, it tends to be +too small near the start of training, when scores are not yet +spread out and $\hat{\sigma}$ is small. This causes the KDE to undersmooth the score +distribution, producing very low gradient magnitudes and stalling convergence. -The solution was to use a bandwidth scheduler. Starting with large bandwidths resulted in gradients that spread out more evenly across all scores, and less non-convergence runs occurred. The bandwidth scheduler artificially scales up the bandwidth at the beginning to speed up initial training, and then tapers back to restore the intended bandwidth in order to maximize resuslts. +The solution was to use a bandwidth scheduler. Starting with large bandwidths resulted in gradients that spread out more evenly across all scores, and fewer non-convergence runs occurred. The bandwidth scheduler artificially scales up the bandwidth at the beginning to speed up initial training, and then tapers back to restore the intended bandwidth in order to maximise results. % TODO: algorithm box — full training loop (forward → ROLL loss → custom backward → weight update) diff --git a/content/related_work/related_work.tex b/content/related_work/related_work.tex index dd1bb4e..23b9288 100644 --- a/content/related_work/related_work.tex +++ b/content/related_work/related_work.tex @@ -84,10 +84,130 @@ TODO finish this section % ============================================================ -% PLACEMENT: near the END of Ch. 2, after KDE and AUC/lit -% review sections, just before the chapter summary. This -% section bridges from prior work to the method chapter by -% framing ROLL as a learnable, gradient-based NP test. +% PLACEMENT: Section 2.5, AFTER the KDE background section +% (sec:kde-background) and BEFORE the Neyman-Pearson bridge +% (sec:neyman-pearson, which becomes 2.6). +% +% Purpose: establish that existing pointwise losses are +% fragile under label corruption, motivating both the +% practical robustness of ROLL and the poisoning experiment +% results in Ch. 4. +% +% Narrative arc: +% 1. Define label noise types: symmetric (uniform flip), +% asymmetric / class-conditional (only certain class +% transitions occur), instance-dependent. Our poisoning +% experiment is asymmetric: P(\tilde{y}=0 \mid y=1)>0, +% P(\tilde{y}=1 \mid y=0)=0. +% 2. Why BCE is fragile: the symmetry condition (Ghosh +% et al., AAAI 2017) — a loss \ell is noise-tolerant +% iff \sum_k \ell(f(x),k) = C (constant). CE fails +% this; MAE satisfies it but converges slowly. Cite +% Feng et al. (IJCAI 2020) for "Can CE be robust?" +% (only under very strict conditions). Implication: +% mislabeled samples produce large unmitigated +% gradients; DNNs memorize noise late in training +% (memorization effect). +% 3. Family of existing fixes — keep brief; these are what +% ROLL sidesteps structurally: +% (a) Robust loss functions: MAE (noise-tolerant, +% slow), GCE (Zhang & Sabuncu, NeurIPS 2018; +% interpolates MAE↔CE via q), asymmetric losses +% (Zhou et al., ICML 2021), symmetrization +% (arXiv:2605.20347). +% (b) Label correction via noise transition matrix +% (Patrini et al., CVPR 2017): estimate +% T[i,j]=P(\tilde{y}=j|y=i), correct logits by +% T^{-1}. Hard for asymmetric noise without a +% clean reference set. +% (c) Sample selection / co-teaching (Han et al., +% NeurIPS 2018): two networks select small-loss +% examples for each other, exploiting the +% memorization effect. Requires dual-model +% training. +% 4. Ranking / distributional objectives and noise +% robustness: pairwise losses depend on score +% differences, not absolute labels — one mislabeled +% sample affects O(n) pairs, each with a small gradient +% weight. Wang et al. (arXiv:2305.14258) formally show +% noise robustness of partial-AUC objectives. +% 5. Bridge (observation, not oversell): ROLL's KDE-based +% distributional objective shares this structural +% property. Fake negatives (copies of positives with +% flipped labels) shift the estimated negative density +% but do not erase distributional separation when true +% positive scores remain clustered. ROLL achieves this +% without any explicit noise-handling mechanism; the +% poisoning experiment in Ch. 4 provides empirical +% evidence. +% ============================================================ +\section{Learning with Noisy Labels} +\label{sec:noisy-labels} + +% SUBSECTION STRUCTURE: +% +% \subsection{Types of Label Noise} +% - Symmetric / uniform: each label flipped with +% probability \varepsilon across all classes. +% - Asymmetric / class-conditional: only certain class +% transitions occur. Our poisoning experiment is of +% this type: P(\tilde{y}=0 \mid y=1)>0, +% P(\tilde{y}=1 \mid y=0)=0. +% - Instance-dependent: flip probability varies per +% sample (hardest to handle; mention only briefly). +% - Note: even moderate noise rates significantly hurt +% pointwise losses in the imbalanced setting, because +% mislabeled positives are rare to begin with. +% +% \subsection{Why Cross-Entropy Is Fragile Under Label Noise} +% - Introduce symmetry condition \cite{ghosh2017robust}: +% a loss is noise-tolerant iff +% \sum_k \ell(f(\mathbf{x}), k) = C (constant). +% - CE does NOT satisfy this; MAE does (but is slow). +% - Memorization effect: DNNs learn clean patterns early, +% then memorize noisy labels late in training. +% - Cite: \cite{ghosh2017robust}, \cite{feng2020can}. +% +% \subsection{Approaches to Robust Learning} +% - Paragraph 1 — Robust loss functions: +% MAE \cite{ghosh2017robust}, +% GCE \cite{zhang2018generalized} (L_q interpolation), +% asymmetric losses \cite{zhou2021asymmetric}. +% Key tradeoff: noise-tolerance vs.\ convergence speed. +% - Paragraph 2 — Transition matrix correction +% \cite{patrini2017making}: forward correction +% multiplies logits by T^{-1}. Canonical method but +% requires estimating T, which is hard for asymmetric +% noise without a clean anchor set. +% - Paragraph 3 — Sample selection / co-teaching +% \cite{han2018coteaching}: two nets select small-loss +% samples for each other each epoch. Bypasses T +% estimation but requires dual-model training. +% +% \subsection{Ranking Objectives and Noise Robustness} +% - Pairwise ranking losses are structurally more +% noise-robust: a single mislabeled sample affects O(n) +% pairs, each with small gradient weight, vs.\ one large +% pointwise gradient in BCE. +% - Cite Wang et al.\ \cite{wang2023weakly} for formal +% treatment in the partial-AUC setting. +% - Close with bridge sentence: ROLL's distributional +% threshold objective operates in the same structural +% regime — not pairwise, but also not pointwise — +% conferring noise robustness without explicit correction. +% Empirical evidence deferred to the Experiments chapter. + +TODO write this section. + +% ============================================================ +% PLACEMENT: Section 2.6 (was 2.5), near the END of Ch. 2, +% after KDE and Noisy Labels sections, just before the +% chapter summary. This section bridges from prior work to +% the method chapter by framing ROLL as a learnable, +% gradient-based NP test. +% NOTE: the label sec:neyman-pearson is unchanged; existing +% \Cref references in Ch. 3 (sec:problem-formulation) still +% work without modification. % ============================================================ \section{Connection to Neyman-Pearson} \label{sec:neyman-pearson} diff --git a/main.tex b/main.tex index 421ceaa..f62904f 100644 --- a/main.tex +++ b/main.tex @@ -236,10 +236,35 @@ \begin{appendices} \chapter{Some title for apendix A} -\label[appendix]{appendix:numerically_distinguished_comp} +\label{appendix:numerically_distinguished_comp} \addtocontents{tocheb}{\contentsline{chapter}{\protect\numberline{נספח א}{\quad\qquadדרישת תאימות כלשהי}}{{\beginL\thepage\endL}}} \input{content/appendixs/appendix_a} +\chapter{Gaussian ROLL: Gradient Derivation} +\label{appendix:gauss-grad} +\addtocontents{tocheb}{\contentsline{chapter}{\protect\numberline{נספח ב}{\quad\qquadנגזרת גאוסיאנית של ROLL}}{{\beginL\thepage\endL}}} +\input{content/appendixs/appendix_gauss_grad} + +\chapter{KDE ROLL: Gradient Derivation} +\label{appendix:kde-grad} +\addtocontents{tocheb}{\contentsline{chapter}{\protect\numberline{נספח ג}{\quad\qquadנגזרת KDE של ROLL}}{{\beginL\thepage\endL}}} +\input{content/appendixs/appendix_kde_grad} + +\chapter{KDE ROLL: Sigmoid Kernel — Explicit Equations} +\label{appendix:kde-sigmoid} +\addtocontents{tocheb}{\contentsline{chapter}{\protect\numberline{נספח ד}{\quad\qquadKDE ROLL: ניסוח מפורש עם גרעין סיגמואיד}}{{\beginL\thepage\endL}}} +\input{content/appendixs/appendix_kde_sigmoid} + +\chapter{KDE ROLL: Bisection for CDF Inversion} +\label{appendix:kde-bisection} +\addtocontents{tocheb}{\contentsline{chapter}{\protect\numberline{נספח ה}{\quad\qquadKDE ROLL: היפוך CDF בשיטת חצייה}}{{\beginL\thepage\endL}}} +\input{content/appendixs/appendix_kde_bisection} + +\chapter{KDE ROLL: Newton--Raphson Inversion (Superseded)} +\label{appendix:kde-nr} +\addtocontents{tocheb}{\contentsline{chapter}{\protect\numberline{נספח ו}{\quad\qquadKDE ROLL: היפוך ניוטון-רפסון}}{{\beginL\thepage\endL}}} +\input{content/appendixs/appendix_kde_nr} + \end{appendices} %~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%