MIRTorch 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. MIRTorch-0.1.0.dist-info/LICENSE +80 -0
  2. MIRTorch-0.1.0.dist-info/METADATA +158 -0
  3. MIRTorch-0.1.0.dist-info/RECORD +43 -0
  4. MIRTorch-0.1.0.dist-info/WHEEL +5 -0
  5. MIRTorch-0.1.0.dist-info/entry_points.txt +2 -0
  6. MIRTorch-0.1.0.dist-info/top_level.txt +1 -0
  7. mirtorch/__init__.py +6 -0
  8. mirtorch/alg/__init__.py +12 -0
  9. mirtorch/alg/cg.py +153 -0
  10. mirtorch/alg/fbpd.py +95 -0
  11. mirtorch/alg/fista.py +87 -0
  12. mirtorch/alg/pogm.py +93 -0
  13. mirtorch/alg/spectral.py +40 -0
  14. mirtorch/alg/util.py +0 -0
  15. mirtorch/dic/__init__.py +5 -0
  16. mirtorch/dic/soup.py +125 -0
  17. mirtorch/dic/util.py +48 -0
  18. mirtorch/linear/__init__.py +58 -0
  19. mirtorch/linear/basics.py +573 -0
  20. mirtorch/linear/linearmaps.py +426 -0
  21. mirtorch/linear/mri.py +689 -0
  22. mirtorch/linear/spect.py +154 -0
  23. mirtorch/linear/util.py +338 -0
  24. mirtorch/linear/wavelets.py +213 -0
  25. mirtorch/prox/__init__.py +21 -0
  26. mirtorch/prox/prox.py +319 -0
  27. mirtorch/vendors/pytorch_wavelets/__init__.py +35 -0
  28. mirtorch/vendors/pytorch_wavelets/_version.py +2 -0
  29. mirtorch/vendors/pytorch_wavelets/dtcwt/__init__.py +6 -0
  30. mirtorch/vendors/pytorch_wavelets/dtcwt/coeffs.py +142 -0
  31. mirtorch/vendors/pytorch_wavelets/dtcwt/lowlevel.py +381 -0
  32. mirtorch/vendors/pytorch_wavelets/dtcwt/lowlevel2.py +663 -0
  33. mirtorch/vendors/pytorch_wavelets/dtcwt/transform2d.py +299 -0
  34. mirtorch/vendors/pytorch_wavelets/dtcwt/transform_funcs.py +495 -0
  35. mirtorch/vendors/pytorch_wavelets/dwt/__init__.py +0 -0
  36. mirtorch/vendors/pytorch_wavelets/dwt/lowlevel.py +997 -0
  37. mirtorch/vendors/pytorch_wavelets/dwt/swt_inverse.py +213 -0
  38. mirtorch/vendors/pytorch_wavelets/dwt/transform1d.py +117 -0
  39. mirtorch/vendors/pytorch_wavelets/dwt/transform2d.py +223 -0
  40. mirtorch/vendors/pytorch_wavelets/scatternet/__init__.py +3 -0
  41. mirtorch/vendors/pytorch_wavelets/scatternet/layers.py +209 -0
  42. mirtorch/vendors/pytorch_wavelets/scatternet/lowlevel.py +779 -0
  43. mirtorch/vendors/pytorch_wavelets/utils.py +243 -0
@@ -0,0 +1,80 @@
1
+ Copyright (c) 2021, Guanhua Wang, Neel Shah, Keyue Zhu and Jeffrey Fessler
2
+
3
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4
+
5
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
6
+
7
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8
+
9
+ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10
+
11
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
12
+
13
+
14
+
15
+ -------------------- LICENSE FOR fastMRI ------------------
16
+
17
+ MIT License
18
+
19
+ Copyright (c) Facebook, Inc. and its affiliates.
20
+
21
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
22
+
23
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
24
+
25
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
+
27
+
28
+ -------------------- LICENSE FOR SigPy ------------------
29
+
30
+ Copyright (c) 2016, Frank Ong.
31
+ Copyright (c) 2016, The Regents of the University of California.
32
+ All rights reserved.
33
+
34
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
35
+
36
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
37
+
38
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
39
+
40
+ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
41
+
42
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43
+
44
+
45
+ ----------------------------- LICENSE FOR numpy-ml --------------------------------
46
+ GNU GENERAL PUBLIC LICENSE
47
+ Version 3, 29 June 2007
48
+
49
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
50
+ Everyone is permitted to copy and distribute verbatim copies
51
+ of this license document, but changing it is not allowed.
52
+
53
+ ----------------------------- LICENSE for pytorch_wavelets----------------------------
54
+ This licence applies to any parts of this library which are novel in comparison
55
+ to the original DTCWT MATLAB toolbox written by Nick Kingsbury and Cian
56
+ Shaffrey. See the Provenance section of README.rst file for details on any further
57
+ restrictions of use. If you wish to use the DTCWT, you should read that license as well.
58
+ The DWT sections come under this license.
59
+
60
+ MIT License
61
+
62
+ Copyright (c) 2020 Fergal Cotter
63
+
64
+ Permission is hereby granted, free of charge, to any person obtaining a copy
65
+ of this software and associated documentation files (the "Software"), to deal
66
+ in the Software without restriction, including without limitation the rights
67
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
68
+ copies of the Software, and to permit persons to whom the Software is
69
+ furnished to do so, subject to the following conditions:
70
+
71
+ The above copyright notice and this permission notice shall be included in all
72
+ copies or substantial portions of the Software.
73
+
74
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
75
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
76
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
77
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
78
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
79
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
80
+ SOFTWARE.
@@ -0,0 +1,158 @@
1
+ Metadata-Version: 2.1
2
+ Name: MIRTorch
3
+ Version: 0.1.0
4
+ Summary: a PyTorch-based image reconstruction toolbox
5
+ Author-email: Guanhua Wang <guanhuaw@umich.edu>
6
+ License: BSD-3-Clause
7
+ Project-URL: repository, https://github.com/guanhuaw/MIRTorch
8
+ Keywords: signal processing,inverse problems
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: BSD License
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Development Status :: 2 - Pre-Alpha
13
+ Classifier: Topic :: Scientific/Engineering :: Image Processing
14
+ Requires-Python: >=3.9
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: torch >=1.13
18
+ Requires-Dist: torchvision
19
+ Requires-Dist: torchkbnufft >=1.4.0
20
+ Requires-Dist: numpy >=1.24
21
+ Requires-Dist: dominate
22
+ Requires-Dist: scipy
23
+ Requires-Dist: PyWavelets
24
+ Requires-Dist: requests
25
+ Requires-Dist: einops
26
+ Requires-Dist: matplotlib
27
+ Requires-Dist: importlib-metadata ; python_version < "3.8"
28
+ Provides-Extra: dev
29
+ Requires-Dist: check-manifest ; extra == 'dev'
30
+ Provides-Extra: test
31
+ Requires-Dist: coverage ; extra == 'test'
32
+ Requires-Dist: pytest ; extra == 'test'
33
+
34
+ # MIRTorch
35
+
36
+ ![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/guanhuaw/mirtorch?include_prereleases)
37
+ ![Read the Docs](https://img.shields.io/readthedocs/mirtorch)
38
+
39
+ A Py***Torch***-based differentiable ***I***mage ***R***econstruction ***T***oolbox, developed at the University of ***M***ichigan.
40
+
41
+ The work is inspired by [MIRT](https://github.com/JeffFessler/mirt), a well-acclaimed toolbox for medical imaging reconstruction.
42
+
43
+ The main objective is to facilitate rapid, data-driven medical image reconstruction using CPUs and GPUs, for fast prototyping. Researchers can conveniently develop new model-based and learning-based methods (e.g., unrolled neural networks) with abstraction layers. The availability of auto-differentiation enables optimization of imaging protocols and reconstruction parameters using gradient methods.
44
+
45
+ Documentation: https://mirtorch.readthedocs.io/en/latest/
46
+
47
+ ------
48
+
49
+ ### Installation
50
+
51
+ We recommend to [pre-install `PyTorch` first](https://pytorch.org/).
52
+ Use `pip install mirtorch` to install.
53
+ To install the `MIRTorch` locally, after cloning the repo, please try `pip install -e .`(one may modify the package locally with this option.)
54
+
55
+ ------
56
+
57
+ ### Features
58
+
59
+ #### Linear maps
60
+
61
+ The `LinearMap` class overloads common matrix operations, such as `+, - , *`.
62
+
63
+ Instances include basic linear operations (like convolution), classical imaging processing, and MRI system matrix (Cartesian and Non-Cartesian, sensitivity- and B0-informed system models). ***NEW!*** MIRTorch recently adds the support for SPECT and CT.
64
+
65
+ Since the Jacobian matrix of a linear operator is itself, the toolbox can actively calculate such Jacobians during backpropagation, avoiding the large cache cost required by auto-differentiation.
66
+
67
+ When defining linear operators, please make sure that all torch tensors are on the same device and compatible. For example, `torch.cfloat` are compatible with `torch.float` but not `torch.double`. Similarly, `torch.chalf` is compatible with `torch.half`.
68
+ When the data is image, there are 2 empirical formats: `[num_batch, num_channel, nx, ny, (nz)]` and `[nx, ny, (nz)]`.
69
+ For some LinearMaps, there is a boolean `batchmode` to control the shape.
70
+
71
+ #### Proximal operators
72
+
73
+ The toolbox contains common proximal operators such as soft thresholding. These operators also support the regularizers that involve multiplication with diagonal or unitary matrices, such as orthogonal wavelets.
74
+
75
+ #### Iterative reconstruction (MBIR) algorithms
76
+
77
+ Currently, the package includes the conjugate gradient (CG), fast iterative thresholding (FISTA), optimized gradient method (POGM), forward-backward primal-dual (FBPD) algorithms for image reconstruction.
78
+
79
+ #### Dictionary learning
80
+
81
+ For dictionary learning-based reconstruction, we implemented an efficient dictionary learning algorithm ([SOUP-DIL](https://arxiv.org/abs/1511.06333)) and orthogonal matching pursuit ([OMP](https://ieeexplore.ieee.org/abstract/document/342465/?casa_token=aTDkQVCM9WEAAAAA:5rXu9YikP822bCBvkhYxKWlBTJ6Fn6baTQJ9kuNrU7K-64EmGOAczYvF2dTW3al3PfPdwJAiYw)). Due to PyTorch’s limited support of sparse matrices, we use SciPy as the backend.
82
+
83
+ #### Multi-GPU support
84
+
85
+ Currently, MIRTorch uses `torch.DataParallel` to support multiple GPUs. One may re-package the `LinearMap`, `Prox` or `Alg` inside a `torch.nn.Module` to enable data parallel. See [this tutorial](https://pytorch.org/tutorials/beginner/blitz/data_parallel_tutorial.html) for detail.
86
+
87
+ ------
88
+
89
+ ### Usage and examples
90
+
91
+ Generally, MIRTorch solves the image reconstruction problems that have the cost function $\textit{argmin}_{x} \|Ax-y\|_2^2 + \lambda \textit{R}(x)$. $A$ stands for the system matrix. When it is linear, one may use `LinearMap` to efficiently compute it. `y` usually denotes measurements. $\textit{R}(\cdot)$ denotes regularizers, which determines which `Alg` to be used. One may refer to [1](https://web.eecs.umich.edu/~fessler/book/), [2](https://web.stanford.edu/~boyd/cvxbook/bv_cvxbook.pdf) and [3](https://www.youtube.com/watch?v=J6_5rPYnr_s) for more tutorials on optimization.
92
+
93
+ Here we provide several notebook tutorials focused on MRI, where $A$ is FFT or NUFFT.
94
+
95
+ - `/example/demo_mnist.ipynb` shows the LASSO on MNIST with FISTA and POGM.
96
+ - `/example/demo_mri.ipynb` contains the SENSE (CG-SENSE) and **B0**-informed reconstruction with penalized weighted least squares (*PWLS*).
97
+ - `/example/demo_3d.ipynb` contains the 3d non-Cartesian MR reconstruction. *New!* Try the Toeplitz-embedding version of B0-informed reconstruction, which reduce hour-long recon to 5 secs.
98
+ - `/example/demo_cs.ipynb` shows the compressed sensing reconstruction of under-determined MRI signals.
99
+ - `/example/demo_dl.ipynb` exhibits the dictionary learning results.
100
+ - `/example/demo_mlem` showcase SPECT recon algorithms, including EM and CNN.
101
+
102
+ Since MIRTorch is differentiable, one may use AD to update many parameters. For example, updating the reconstruction neural network's weights. More importantly, one may update the imaging system itself via gradient-based and data-driven methods. As a user case, [Bjork repo](https://github.com/guanhuaw/Bjork) contains MRI sampling pattern optimization examples. One may use the reconstruction loss as the objective function to jointly optimize reconstruction algorithms and the sampling pattern. See [this video](https://www.youtube.com/watch?v=sLFOf5EvVAs) on how to jointly optimize reconstruction and acquisition.
103
+
104
+ ------
105
+
106
+ ### Acknowledgments
107
+
108
+ This work is inspired by (but not limited to):
109
+
110
+ * SigPy: https://github.com/mikgroup/sigpy
111
+
112
+ * MIRT: https://github.com/JeffFessler/mirt
113
+
114
+ * MIRT.jl: https://github.com/JeffFessler/MIRT.jl
115
+
116
+ * PyLops: https://github.com/PyLops/pylops
117
+
118
+ If the code is useful to your research, please consider citing:
119
+
120
+ ```bibtex
121
+ @article{wang:22:bjork,
122
+ author={Wang, Guanhua and Luo, Tianrui and Nielsen, Jon-Fredrik and Noll, Douglas C. and Fessler, Jeffrey A.},
123
+ journal={IEEE Transactions on Medical Imaging},
124
+ title={B-spline Parameterized Joint Optimization of Reconstruction and K-space Trajectories ({BJORK}) for Accelerated {2D} {MRI}},
125
+ year={2022},
126
+ pages={1-1},
127
+ doi={10.1109/TMI.2022.3161875}}
128
+ ```
129
+
130
+ ```bibtex
131
+ @inproceedings{wang:22:mirtorch,
132
+ title={{MIRTorch}: A {PyTorch}-powered Differentiable Toolbox for Fast Image Reconstruction and Scan Protocol Optimization},
133
+ author={Wang, Guanhua and Shah, Neel and Zhu, Keyue and Noll, Douglas C. and Fessler, Jeffrey A.},
134
+ booktitle={Proc. Intl. Soc. Magn. Resonance. Med. (ISMRM)},
135
+ pages={4982},
136
+ year={2022}
137
+ }
138
+ ```
139
+ If you use the SPECT code, please consider citing:
140
+
141
+ ```bibtex
142
+ @ARTICLE{li:23:tet,
143
+ author={Li, Zongyu and Dewaraja, Yuni K. and Fessler, Jeffrey A.},
144
+ journal={IEEE Transactions on Radiation and Plasma Medical Sciences},
145
+ title={Training End-to-End Unrolled Iterative Neural Networks for SPECT Image Reconstruction},
146
+ year={2023},
147
+ volume={7},
148
+ number={4},
149
+ pages={410-420},
150
+ doi={10.1109/TRPMS.2023.3240934}}
151
+ ```
152
+
153
+
154
+ ------
155
+
156
+ ### License
157
+
158
+ This package uses the BSD3 license.
@@ -0,0 +1,43 @@
1
+ mirtorch/__init__.py,sha256=M7cAwxRzIFuSAR126GlDF8wBsUbMMm7AtUi_unf1BXQ,148
2
+ mirtorch/alg/__init__.py,sha256=COQtui_W-ewqJgkdPack-qGwUvKvHBSB_j8dkeNpwE8,274
3
+ mirtorch/alg/cg.py,sha256=HJf1ar4Kik2csEAB9XmpKVzQzG_0JRfR5SPx2bgR9-U,4812
4
+ mirtorch/alg/fbpd.py,sha256=RSL7b1PRkDHegWVDB9IL5fv0-_hAcn02zWRo_22eJ9Y,3022
5
+ mirtorch/alg/fista.py,sha256=aQfhpvZ_-aQeU4NNtSOTvTYngzSUE9AGCEIXRkb_0B8,2462
6
+ mirtorch/alg/pogm.py,sha256=2gPvoWnCq6qzpntd7Rc5SmFxGIVWdqh3sRZyZGbbKDo,2836
7
+ mirtorch/alg/spectral.py,sha256=pxXDNXq6hbZ9e6PKtgVyX-MD3_-oAsyK7lfv9p79FB4,1138
8
+ mirtorch/alg/util.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ mirtorch/dic/__init__.py,sha256=z1wRn1Uu-UtcDq_1vmg3p3C6Aw7PFr7DKhyPWhGodzg,170
10
+ mirtorch/dic/soup.py,sha256=BGPnoGmfU8lmdvA5ZlTAFlrQ3NzQxock7fXnzodlKMU,5005
11
+ mirtorch/dic/util.py,sha256=ENoServ5AVIWkJKiiCVbN-r-namcU7k1_hmG576rGRc,1631
12
+ mirtorch/linear/__init__.py,sha256=W4KMwJpVBcvJDIoTcZSD1LPuJ2V_xlUTVtGjM_kaa6Y,902
13
+ mirtorch/linear/basics.py,sha256=FVo724snDeAA8HqoqHsuS29nudpW-ImqUDYDgrBktqI,17406
14
+ mirtorch/linear/linearmaps.py,sha256=EKJiJ_vZ6dsIiRKA-0za-yA1CSZ4rB4PWv4iQzQMv_U,12743
15
+ mirtorch/linear/mri.py,sha256=WjKocD7cFs3JPgtto1-vgdbW1gHUbH75-5ySdMkU618,25988
16
+ mirtorch/linear/spect.py,sha256=XGoBvRy9AwE29BhwlgR5UTcnQl61UbR2vk_RTiO7ego,4750
17
+ mirtorch/linear/util.py,sha256=ycEoLKeSSzgkWeA3tBLReQkj2PyHaUDJJ0GrbbIVsIg,8283
18
+ mirtorch/linear/wavelets.py,sha256=KajzFw87_UznsApjQvtwT4Pubb8FBTYNOPTiVJ8WeU8,7494
19
+ mirtorch/prox/__init__.py,sha256=UWEScui-abN47vly_Reg-7TOYf5-FhOZQis1t5kyeso,319
20
+ mirtorch/prox/prox.py,sha256=QnFioBgOKnESvQ9bKZsHA1OGixHEkEoORU1iw-fdC78,9681
21
+ mirtorch/vendors/pytorch_wavelets/__init__.py,sha256=ukA3rF0vBjLlpd9CaxxW4wFPXTm5Q2eh-rlcRH2EBs4,667
22
+ mirtorch/vendors/pytorch_wavelets/_version.py,sha256=T9mHhV6eqKSKtCKDrltAYNNplh9SlVM1qRWp6oBp9CM,95
23
+ mirtorch/vendors/pytorch_wavelets/utils.py,sha256=fGRjZwndXEdQqp8xBnf3rYL5UeLj5Qb3LVTZisvbe5E,7762
24
+ mirtorch/vendors/pytorch_wavelets/dtcwt/__init__.py,sha256=6j3Ds3Bk_3EMQSAY-S96U8itjCKh3bIjay0iFy0JC5g,173
25
+ mirtorch/vendors/pytorch_wavelets/dtcwt/coeffs.py,sha256=-wy3-p0YxGzEOkcHY-35qGj1TwMnT7zYVFLszb4Q5-I,4174
26
+ mirtorch/vendors/pytorch_wavelets/dtcwt/lowlevel.py,sha256=uH8JR7DF8oC2rtVGN7dG06u_V-C1AK7h7V77_hCWCX0,10511
27
+ mirtorch/vendors/pytorch_wavelets/dtcwt/lowlevel2.py,sha256=xBgYeJlN-2615L34Bk2CMP0ZO7e8kS9dUKzjTCFj3E4,24984
28
+ mirtorch/vendors/pytorch_wavelets/dtcwt/transform2d.py,sha256=gPeLeiR58tNWHdtCfEHgZOfJYMMpROWpqIbKvYMYuDs,11185
29
+ mirtorch/vendors/pytorch_wavelets/dtcwt/transform_funcs.py,sha256=-4QL4Ri8K5wufsFV8CFB2iTla_OldNQ2vd0oBLkxzkc,17008
30
+ mirtorch/vendors/pytorch_wavelets/dwt/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
+ mirtorch/vendors/pytorch_wavelets/dwt/lowlevel.py,sha256=NlIIE7COdbYUUIF3zE6hctRz_VodlJDO0mtdu7ynxME,36173
32
+ mirtorch/vendors/pytorch_wavelets/dwt/swt_inverse.py,sha256=wnPc2Qaj6skSOMS1MJP5J89jee9NjicX885DwrtPviw,8187
33
+ mirtorch/vendors/pytorch_wavelets/dwt/transform1d.py,sha256=-hlErWgapPh073AXvDYua5waOUY5dWdf-iEB6LmRGog,3784
34
+ mirtorch/vendors/pytorch_wavelets/dwt/transform2d.py,sha256=0BvE8suR9PDCihMXMxbgSS_BieC8xv1csLtQmpsrkKM,8070
35
+ mirtorch/vendors/pytorch_wavelets/scatternet/__init__.py,sha256=XfquxUhTyrDV_bvL6FV4eUsqK6C4eA0ib-kZUEfk5Fk,83
36
+ mirtorch/vendors/pytorch_wavelets/scatternet/layers.py,sha256=Tu1eDSoxypnaDJMcpjxpIzZjrXHW-7yaxMZkKyz0Dug,7851
37
+ mirtorch/vendors/pytorch_wavelets/scatternet/lowlevel.py,sha256=kKzagY0QOM5y2mRQtqWfxHQzW3iqaTvluZyObgrelNQ,25205
38
+ MIRTorch-0.1.0.dist-info/LICENSE,sha256=vlr6JcRY9pCrasK99KDlTAMdtJPiiy3-LtQahoWrTGU,6112
39
+ MIRTorch-0.1.0.dist-info/METADATA,sha256=oOHvZurBaKEGsbmx9JcjPRm-13Ly65WLxTDXnahOtLo,8168
40
+ MIRTorch-0.1.0.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
41
+ MIRTorch-0.1.0.dist-info/entry_points.txt,sha256=iq9Cu1AYMLWEh9jhFJ5t5hC3ma-xEfRs9gSPRWeyRzI,57
42
+ MIRTorch-0.1.0.dist-info/top_level.txt,sha256=flms4ycMQuWT7P7BxFBIeoTRBbpzLoa-R9zpYypDiQU,9
43
+ MIRTorch-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (72.1.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ my-script = my_package.module:function
@@ -0,0 +1 @@
1
+ mirtorch
mirtorch/__init__.py ADDED
@@ -0,0 +1,6 @@
1
+ from mirtorch import prox
2
+ from mirtorch import linear
3
+ from mirtorch import alg
4
+ from mirtorch import dic
5
+
6
+ __all__ = ["linear", "prox", "alg", "dic"]
@@ -0,0 +1,12 @@
1
+ import logging
2
+
3
+ from .cg import CG
4
+ from .spectral import power_iter
5
+ from .pogm import POGM
6
+ from .fista import FISTA
7
+ from .fbpd import FBPD
8
+
9
+ logging.basicConfig(level=logging.INFO)
10
+ logger = logging.getLogger(__name__)
11
+
12
+ __all__ = ["CG", "power_iter", "POGM", "FISTA", "FBPD"]
mirtorch/alg/cg.py ADDED
@@ -0,0 +1,153 @@
1
+ import torch
2
+ import logging
3
+ from torch import Tensor
4
+
5
+ logger = logging.getLogger(__name__)
6
+
7
+
8
+ class CG_func(torch.autograd.Function):
9
+ @staticmethod
10
+ def forward(ctx, b: Tensor, A, max_iter, tol, alert, x0, eval_func, P):
11
+ ctx.save_for_backward(b)
12
+ ctx.A = A
13
+ ctx.max_iter = max_iter
14
+ ctx.tol = tol
15
+ ctx.alert = alert
16
+ ctx.eval_func = eval_func
17
+ ctx.P = P
18
+ return cg_block(x0, b, A, tol, max_iter, alert, eval_func, P)
19
+
20
+ @staticmethod
21
+ def backward(ctx, dx):
22
+ b = ctx.saved_tensors[0]
23
+ # a better initialization?
24
+ return (
25
+ cg_block(
26
+ b, dx, ctx.A, ctx.tol, ctx.max_iter, ctx.alert, ctx.eval_func, ctx.P
27
+ ),
28
+ None,
29
+ None,
30
+ None,
31
+ None,
32
+ None,
33
+ None,
34
+ None,
35
+ )
36
+
37
+
38
+ def cg_block(x0, b, A, tol, max_iter, alert, eval_func, P):
39
+ # solver for PSD Ax = b
40
+ if P is None:
41
+ r0 = b - A * x0
42
+ rk = r0
43
+ p0 = r0.detach().clone()
44
+ pk = p0
45
+ xk = x0.detach().clone()
46
+ rktrk = torch.square(torch.norm(rk))
47
+ num_loop = 0
48
+ if eval_func is not None:
49
+ saved = []
50
+ while rktrk.item() > tol and num_loop < max_iter:
51
+ pktapk = torch.sum(pk.conj() * (A * pk)).abs()
52
+ alpha = rktrk / pktapk
53
+ xk1 = xk.add_(alpha * pk)
54
+ rk1 = rk.sub_(alpha * A * pk)
55
+ rk1trk1 = torch.square(torch.norm(rk1))
56
+ beta = rk1trk1 / rktrk
57
+ pk1 = (pk.mul_(beta)).add_(rk1)
58
+ xk = xk1
59
+ rk = rk1
60
+ pk = pk1
61
+ rktrk = rk1trk1
62
+ num_loop = num_loop + 1
63
+ if eval_func is not None:
64
+ saved.append(eval_func(rk))
65
+ if alert:
66
+ logger.info(
67
+ "Residual at %dth iter in forward CG: %10.3e." % (num_loop, rktrk)
68
+ )
69
+ else:
70
+ r0 = b - A * x0
71
+ rk = r0
72
+ zk = P * rk
73
+ pk = zk.clone()
74
+ xk = x0.detach().clone()
75
+ rktzk = (rk.conj() * zk).sum().abs()
76
+ num_loop = 0
77
+ if eval_func is not None:
78
+ saved = []
79
+ while torch.square(torch.norm(rk)).item() > tol and num_loop < max_iter:
80
+ pktapk = torch.sum(pk.conj() * (A * pk)).abs()
81
+ alpha = rktzk / pktapk
82
+ xk1 = xk.add_(alpha * pk)
83
+ rk1 = rk.sub_(alpha * A * pk)
84
+ zk1 = P * rk1
85
+ rk1tzk1 = (rk1.conj() * zk1).sum().abs()
86
+ beta = rk1tzk1 / rktzk
87
+ pk1 = (pk.mul_(beta)).add_(zk1)
88
+ xk = xk1
89
+ rk = rk1
90
+ pk = pk1
91
+ rktzk = rk1tzk1
92
+ num_loop = num_loop + 1
93
+ if eval_func is not None:
94
+ saved.append(eval_func(rk))
95
+ if alert:
96
+ logger.info(
97
+ "Residual at %dth iter in CG backpropagation: %10.3e."
98
+ % (num_loop, rktzk)
99
+ )
100
+ if torch.cuda.is_available():
101
+ logging.info(
102
+ "GPU memory usage at %dth iter in CG backpropagation: %10.3e."
103
+ % (num_loop, torch.cuda.memory_allocated() / 1024 / 1024 / 1024)
104
+ )
105
+
106
+ if eval_func is not None:
107
+ return xk, saved
108
+ else:
109
+ return xk
110
+
111
+
112
+ class CG:
113
+ r"""
114
+ Solve the equation :math:`Ax = b` with the conjugdate gradient (CG) method, where A is a positive semi-definite operator.
115
+ The backpropagation still calls the CG to calculate the Jacobian to save the memory.
116
+
117
+ Attributes:
118
+ A: LinearMap of a PSD matrix
119
+ tol: float, exiting tolerance
120
+ max_iter: int, max number of iterations
121
+ alert: bool, print the norm of residuals at the end
122
+ eval_func: user-defined function to calculate the loss at each iteration.
123
+ P: LinearMap of a Preconditioner
124
+
125
+ Methods:
126
+ run: run the CG algorithm
127
+ """
128
+
129
+ def __init__(self, A, max_iter=20, tol=1e-2, P=None, alert=False, eval_func=None):
130
+ self.solver = CG_func.apply
131
+ self.A = A
132
+ self.max_iter = max_iter
133
+ self.tol = tol
134
+ self.solver = CG_func.apply
135
+ self.alert = alert
136
+ self.eval_func = eval_func
137
+ self.P = P
138
+
139
+ def run(self, x0, b):
140
+ r"""Run the CG iterations.
141
+ Args:
142
+ x0: Initialization
143
+ b: RHS
144
+
145
+ Returns:
146
+ xk: results
147
+ saved: (optional) a list of intermediate results, calculated by the eval_func.
148
+ """
149
+ if list(self.A.size_out) != list(b.shape):
150
+ raise ValueError("The size of A and b do not match.")
151
+ return self.solver(
152
+ b, self.A, self.max_iter, self.tol, self.alert, x0, self.eval_func, self.P
153
+ )
mirtorch/alg/fbpd.py ADDED
@@ -0,0 +1,95 @@
1
+ from typing import Callable
2
+ import logging
3
+
4
+ import torch
5
+ from mirtorch.prox import Prox, Conj
6
+ from mirtorch.linear import LinearMap
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ class FBPD:
12
+ r"""Forward-backward primal dual (FBPD) algorithm.
13
+
14
+ Ref:
15
+ L. Condat, A primal dual splitting method for convex optimization involving
16
+ Lipschitzian, proximable and linear composite terms. Journal of Optimization Theory
17
+ and Applications, 158(2):460-479, 2013.
18
+
19
+ The cost function is:
20
+
21
+ .. math::
22
+
23
+ arg \min_x f(x) + g(x) + h(Gx)
24
+
25
+ where f and h are proper convex functions, and g is a convex function with a L-Lipschitz continuous gradient.
26
+
27
+ Attributes:
28
+ g_grad: Callable to calculate the gradient of g
29
+ f_prox: Prox: proximal operator of f
30
+ h_prox: Prox: proximal operator of h
31
+ g_L: float, Lipschitz value of g_grad
32
+ G_norm: float of the norm of G'G, can be solved by power_iter()
33
+ tau: float, step size
34
+ max_iter: int, number of iterations to run
35
+ eval_func: user-defined function to calculate the loss at each iteration.
36
+ """
37
+
38
+ def __init__(
39
+ self,
40
+ g_grad: Callable,
41
+ f_prox: Prox,
42
+ h_prox: Prox,
43
+ g_L: float,
44
+ G_norm: float,
45
+ G: LinearMap | None = None,
46
+ tau: float | None = None,
47
+ max_iter: int = 10,
48
+ eval_func: Callable | None = None,
49
+ p: int = 1,
50
+ ):
51
+ self.max_iter = max_iter
52
+ self.g_grad = g_grad
53
+ self.f_prox = f_prox
54
+ self.h_prox = h_prox
55
+ self.h_conj_prox = Conj(self.h_prox)
56
+ self.g_L = g_L
57
+ self.G = G
58
+ self.G_norm = G_norm
59
+ self.p = p
60
+ if tau is None:
61
+ self.tau = 2.0 / (g_L + 2.0)
62
+ else:
63
+ self.tau = tau
64
+ self.sigma = (1.0 / self.tau - self.g_L / 2.0) / self.G_norm
65
+ self.eval_func = eval_func
66
+
67
+ def run(self, x0: torch.Tensor):
68
+ r"""
69
+ Run the algorithm
70
+ Args:
71
+ x0: tensor, initialization
72
+ Returns:
73
+ xk: tensor, results
74
+ saved: (optional) a list of intermediate results, calcuated by the eval_func.
75
+ """
76
+ uold = self.G * x0
77
+ xold = x0
78
+ if self.eval_func is not None:
79
+ saved = []
80
+ for i in range(1, self.max_iter + 1):
81
+ xold_bar = self.g_grad(xold) + self.G.H * uold
82
+ xnew = self.f_prox(xold - self.tau * xold_bar, self.tau)
83
+ uold_bar = self.G * (2 * xnew - xold)
84
+ unew = self.h_conj_prox(uold + self.sigma * uold_bar, self.sigma)
85
+ xold = self.p * xnew + (1 - self.p) * xold
86
+ uold = self.p * unew + (1 - self.p) * uold
87
+ if self.eval_func is not None:
88
+ saved.append(self.eval_func(xold))
89
+ logger.info(
90
+ "The cost function at %dth iter in FBPD: %10.3e.", i, saved[-1]
91
+ )
92
+ if self.eval_func is not None:
93
+ return xold, saved
94
+ else:
95
+ return xold
mirtorch/alg/fista.py ADDED
@@ -0,0 +1,87 @@
1
+ from mirtorch.prox import Prox
2
+ import numpy as np
3
+ import torch
4
+ from typing import Callable
5
+ import logging
6
+
7
+ logger = logging.getLogger(__name__)
8
+
9
+
10
+ class FISTA:
11
+ r"""
12
+ Fast Iterative Soft Thresholding Algorithm (FISTA) / Fast Proximal Gradient Method (FPGM)
13
+
14
+ .. math::
15
+
16
+ arg \min_x f(x) + g(x)
17
+
18
+ where grad(f(x)) is L-Lipschitz continuous and g is proximal-friendly function.
19
+
20
+ Attributes:
21
+ max_iter (int): number of iterations to run
22
+ f_grad (Callable): gradient of f
23
+ f_L (float): L-Lipschitz value of f_grad
24
+ g_prox (Prox): proximal operator g
25
+ restart (Union[...]): restart strategy, not yet implemented
26
+ eval_func: user-defined function to calculate the loss at each iteration.
27
+ """
28
+
29
+ def __init__(
30
+ self,
31
+ f_grad: Callable,
32
+ f_L: float,
33
+ g_prox: Prox,
34
+ max_iter: int = 10,
35
+ restart=False,
36
+ eval_func: Callable = None,
37
+ ):
38
+ self.max_iter = max_iter
39
+ self.f_grad = f_grad
40
+ self.f_L = f_L
41
+ self.prox = g_prox
42
+ self._alpha = 1 / self.f_L # value for 1/L
43
+ self.eval_func = eval_func
44
+ if restart:
45
+ raise NotImplementedError
46
+ self.restart = restart
47
+
48
+ def run(self, x0: torch.Tensor):
49
+ r"""
50
+ Run the algorithm
51
+
52
+ Args:
53
+ x0: initialization
54
+
55
+ Returns:
56
+ xk: results
57
+ saved: (optional) a list of intermediate results, calcuated by the eval_func.
58
+ """
59
+
60
+ def _update_momentum():
61
+ nonlocal told, beta
62
+ tnew = 0.5 * (1 + np.sqrt(1 + 4 * told**2))
63
+ beta = (told - 1) / tnew
64
+ told = tnew
65
+
66
+ # initialize parameters
67
+ xold = x0
68
+ yold = x0
69
+ told = 1.0
70
+ beta = 0.0
71
+ if self.eval_func is not None:
72
+ saved = []
73
+ for i in range(1, self.max_iter + 1):
74
+ fgrad = self.f_grad(xold)
75
+ ynew = self.prox(xold - self._alpha * fgrad, self._alpha)
76
+ _update_momentum()
77
+ xnew = ynew + beta * (ynew - yold)
78
+ xold = xnew
79
+ yold = ynew
80
+ # log the cost function
81
+ if self.eval_func is not None:
82
+ saved.append(self.eval_func(xold))
83
+ logger.info(f"Cost function at {i}th iteration: {self.eval_func(xold)}")
84
+ if self.eval_func is not None:
85
+ return xold, saved
86
+ else:
87
+ return xold