Repository navigation
ProxSkip algorithm - #2267
ProxSkip algorithm#2267epapoutsellis wants to merge 9 commits into
Conversation
|
Thanks Vaggelis, this looks like a great addition. I'll add it to the work plan and make sure it gets prioritised for review. |
| class ProxSkip(Algorithm): | ||
|
|
||
|
|
||
| r"""Proximal Skip (ProxSkip) algorithm, see "ProxSkip: Yes! Local Gradient Steps Provably Lead to Communication Acceleration! Finally!†" |
gfardell
left a comment
There was a problem hiding this comment.
Hi @epapoutsellis, I have added some comments. Please let me know when you are ready for me to review, or if you need any support in addressing them. I haven't looked closely at the unit tests yet.
| def _update_previous_solution(self): | ||
| """ Swaps the references to current and previous solution based on the :func:`~Algorithm.update_previous_solution` of the base class :class:`Algorithm`. | ||
| """ | ||
| tmp = self.x_new | ||
| self.x = self.x_new | ||
| self.x = tmp |
There was a problem hiding this comment.
This isn't switching the references as intended. Instead it's orphaning the buffer that was at self.x.
| self.g.proximal(self.xhat_new - (self.step_size/self.prob)*self.ht, self.step_size/self.prob, out=self.x_new) | ||
| self.ht.sapyb(1., (self.x_new - self.xhat_new), (self.prob/self.step_size), out=self.ht) |
There was a problem hiding this comment.
These are both allocating new ImageData's for the intermediate steps. This should use a preallocated buffer.
There was a problem hiding this comment.
Added new buffer.
| # convention: use proximal in the first iteration | ||
| if self.iteration==0: | ||
| theta = True | ||
| self.thetas.append(theta) |
There was a problem hiding this comment.
Is there a reason to log these?
There was a problem hiding this comment.
It is useful for the user to see where proximal is computed. I created a new function that can be called after running the algo.
| if self.prob<=0: | ||
| raise ValueError("Need a positive probability") | ||
| if self.prob==1: | ||
| raise warn("If p=1, ProxSkip is equivalent to ISTA/PGD. Please use ISTA/PGD to avoid computing updates of the control variate that is not used.") |
There was a problem hiding this comment.
This should be a warnings.warn() not raise warn. It also should have a unit test check.
|
|
||
| logging.info("{} setting up".format(self.__class__.__name__, )) | ||
|
|
||
| ## TODO better to use different initials for x and h. |
| self.xhat_new -= self.ht | ||
| self.x.sapyb(1., self.xhat_new, -self.step_size, out=self.xhat_new) | ||
|
|
||
| theta = self.rng.random() < self.prob |
There was a problem hiding this comment.
If prob=1, theata is true and proximal step is called. But the docstring says prob is the probability to skip the proximal step.
| @@ -0,0 +1,112 @@ | |||
| from cil.optimisation.algorithms import Algorithm | |||
There was a problem hiding this comment.
No file header. It should be the licence and you added as a contibutor. As a note we also should update your instituation in the notice.txt
|
|
||
| self.configured = True | ||
|
|
||
| logging.info("{} configured".format(self.__class__.__name__, )) |
There was a problem hiding this comment.
The module log should be created at the top of the file with
log = logging.getLogger(__name__) then log.info()
| A convex function with a "simple" proximal. | ||
| prob : positive :obj:`float` | ||
| Probability to skip the proximal step. If :code:`prob=1`, proximal step is used in every iteration. | ||
| step_size : positive :obj:`float` |
There was a problem hiding this comment.
Could this accept a StepSizeRule as Ista and Fista do?
There was a problem hiding this comment.
Similarly, can it take a preconditioner like ISTA or FISTA??
There was a problem hiding this comment.
The reason that I do not inherit for ISTA is that at the moment there is no theory for adaptive step sizes or precond when skipping. Only heuristic choices that are not necessarily faster (in time) compared to a ISTA. So I think is dangerous for the users to allow this option.
| logging.info("{} setting up".format(self.__class__.__name__, )) | ||
|
|
||
| ## TODO better to use different initials for x and h. | ||
| self.initial = initial |
There was a problem hiding this comment.
This adds a reference to initial that is never used.
|
|
||
|
|
||
| r"""Proximal Skip (ProxSkip) algorithm, see "ProxSkip: Yes! Local Gradient Steps Provably Lead to Communication Acceleration! Finally!†" | ||
|
|
There was a problem hiding this comment.
Could we also add a few lines about what optimisation objective the algorithm solves and why you would want to use it?
| from warnings import warn | ||
|
|
||
|
|
||
| class ProxSkip(Algorithm): |
There was a problem hiding this comment.
Is there a reason it is not a subclass of ISTA/PGD?
There was a problem hiding this comment.
The reason that I do not inherit for ISTA is that at the moment there is no theory for adaptive step sizes or precond when skipping. Only heuristic choices that are not necessarily faster (in time) compared to a ISTA. So I think is dangerous for the users to allow this option.
| A convex function with a "simple" proximal. | ||
| prob : positive :obj:`float` | ||
| Probability to skip the proximal step. If :code:`prob=1`, proximal step is used in every iteration. | ||
| step_size : positive :obj:`float` |
There was a problem hiding this comment.
Similarly, can it take a preconditioner like ISTA or FISTA??
|
Thank you @gfardell @MargaretDuff for your reviews . I've made a few changes to address your comments. |
Signed-off-by: Vaggelis Papoutsellis <22398586+epapoutsellis@users.noreply.github.com>
|
@epapoutsellis thanks! I will take another look in the next week. |
Description
close #2266
Example Usage
Contribution Notes
❤️ Thanks for your contribution!