AOT-biomaps 2.1.3__py3-none-any.whl → 2.9.233__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.
Potentially problematic release.
This version of AOT-biomaps might be problematic. Click here for more details.
- AOT_biomaps/AOT_Acoustic/AcousticEnums.py +64 -0
- AOT_biomaps/AOT_Acoustic/AcousticTools.py +221 -0
- AOT_biomaps/AOT_Acoustic/FocusedWave.py +244 -0
- AOT_biomaps/AOT_Acoustic/IrregularWave.py +66 -0
- AOT_biomaps/AOT_Acoustic/PlaneWave.py +43 -0
- AOT_biomaps/AOT_Acoustic/StructuredWave.py +392 -0
- AOT_biomaps/AOT_Acoustic/__init__.py +15 -0
- AOT_biomaps/AOT_Acoustic/_mainAcoustic.py +978 -0
- AOT_biomaps/AOT_Experiment/Focus.py +55 -0
- AOT_biomaps/AOT_Experiment/Tomography.py +505 -0
- AOT_biomaps/AOT_Experiment/__init__.py +9 -0
- AOT_biomaps/AOT_Experiment/_mainExperiment.py +532 -0
- AOT_biomaps/AOT_Optic/Absorber.py +24 -0
- AOT_biomaps/AOT_Optic/Laser.py +70 -0
- AOT_biomaps/AOT_Optic/OpticEnums.py +17 -0
- AOT_biomaps/AOT_Optic/__init__.py +10 -0
- AOT_biomaps/AOT_Optic/_mainOptic.py +204 -0
- AOT_biomaps/AOT_Recon/AOT_Optimizers/DEPIERRO.py +191 -0
- AOT_biomaps/AOT_Recon/AOT_Optimizers/LS.py +106 -0
- AOT_biomaps/AOT_Recon/AOT_Optimizers/MAPEM.py +456 -0
- AOT_biomaps/AOT_Recon/AOT_Optimizers/MLEM.py +333 -0
- AOT_biomaps/AOT_Recon/AOT_Optimizers/PDHG.py +221 -0
- AOT_biomaps/AOT_Recon/AOT_Optimizers/__init__.py +5 -0
- AOT_biomaps/AOT_Recon/AOT_PotentialFunctions/Huber.py +90 -0
- AOT_biomaps/AOT_Recon/AOT_PotentialFunctions/Quadratic.py +86 -0
- AOT_biomaps/AOT_Recon/AOT_PotentialFunctions/RelativeDifferences.py +59 -0
- AOT_biomaps/AOT_Recon/AOT_PotentialFunctions/__init__.py +3 -0
- AOT_biomaps/AOT_Recon/AlgebraicRecon.py +1023 -0
- AOT_biomaps/AOT_Recon/AnalyticRecon.py +154 -0
- AOT_biomaps/AOT_Recon/BayesianRecon.py +230 -0
- AOT_biomaps/AOT_Recon/DeepLearningRecon.py +35 -0
- AOT_biomaps/AOT_Recon/PrimalDualRecon.py +210 -0
- AOT_biomaps/AOT_Recon/ReconEnums.py +375 -0
- AOT_biomaps/AOT_Recon/ReconTools.py +273 -0
- AOT_biomaps/AOT_Recon/__init__.py +11 -0
- AOT_biomaps/AOT_Recon/_mainRecon.py +288 -0
- AOT_biomaps/Config.py +95 -0
- AOT_biomaps/Settings.py +45 -13
- AOT_biomaps/__init__.py +271 -18
- aot_biomaps-2.9.233.dist-info/METADATA +22 -0
- aot_biomaps-2.9.233.dist-info/RECORD +43 -0
- {AOT_biomaps-2.1.3.dist-info → aot_biomaps-2.9.233.dist-info}/WHEEL +1 -1
- AOT_biomaps/AOT_Acoustic.py +0 -1881
- AOT_biomaps/AOT_Experiment.py +0 -541
- AOT_biomaps/AOT_Optic.py +0 -219
- AOT_biomaps/AOT_Reconstruction.py +0 -1416
- AOT_biomaps/config.py +0 -54
- AOT_biomaps-2.1.3.dist-info/METADATA +0 -20
- AOT_biomaps-2.1.3.dist-info/RECORD +0 -11
- {AOT_biomaps-2.1.3.dist-info → aot_biomaps-2.9.233.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
from AOT_biomaps.AOT_Recon.ReconEnums import PotentialType
|
|
2
|
+
from AOT_biomaps.AOT_Recon.AOT_PotentialFunctions.Quadratic import _Omega_QUADRATIC_CPU, _Omega_QUADRATIC_GPU
|
|
3
|
+
from AOT_biomaps.AOT_Recon.AOT_PotentialFunctions.RelativeDifferences import _Omega_RELATIVE_DIFFERENCE_CPU, _Omega_RELATIVE_DIFFERENCE_GPU
|
|
4
|
+
from AOT_biomaps.AOT_Recon.AOT_PotentialFunctions.Huber import _Omega_HUBER_PIECEWISE_CPU, _Omega_HUBER_PIECEWISE_GPU
|
|
5
|
+
from AOT_biomaps.AOT_Recon.ReconTools import _build_adjacency_sparse, check_gpu_memory, calculate_memory_requirement
|
|
6
|
+
from AOT_biomaps.Config import config
|
|
7
|
+
|
|
8
|
+
import warnings
|
|
9
|
+
import numpy as np
|
|
10
|
+
import torch
|
|
11
|
+
from tqdm import trange
|
|
12
|
+
|
|
13
|
+
def MAPEM(
|
|
14
|
+
SMatrix,
|
|
15
|
+
y,
|
|
16
|
+
Omega,
|
|
17
|
+
beta,
|
|
18
|
+
delta=None,
|
|
19
|
+
gamma=None,
|
|
20
|
+
sigma=None,
|
|
21
|
+
numIterations=100,
|
|
22
|
+
isSavingEachIteration=True,
|
|
23
|
+
withTumor=True,
|
|
24
|
+
device=None,
|
|
25
|
+
max_saves=5000,
|
|
26
|
+
show_logs=True):
|
|
27
|
+
"""
|
|
28
|
+
This method implements the MAPEM algorithm using either CPU or single-GPU PyTorch acceleration.
|
|
29
|
+
Multi-GPU and Multi-CPU modes are not implemented for this algorithm.
|
|
30
|
+
"""
|
|
31
|
+
try:
|
|
32
|
+
tumor_str = "WITH" if withTumor else "WITHOUT"
|
|
33
|
+
# Auto-select device and method
|
|
34
|
+
if device is None:
|
|
35
|
+
if torch.cuda.is_available() and check_gpu_memory(config.select_best_gpu(), calculate_memory_requirement(SMatrix, y), show_logs=show_logs):
|
|
36
|
+
device = torch.device(f"cuda:{config.select_best_gpu()}")
|
|
37
|
+
use_gpu = True
|
|
38
|
+
else:
|
|
39
|
+
device = torch.device("cpu")
|
|
40
|
+
use_gpu = False
|
|
41
|
+
else:
|
|
42
|
+
use_gpu = device.type == "cuda"
|
|
43
|
+
# Dispatch to the appropriate implementation
|
|
44
|
+
if use_gpu:
|
|
45
|
+
return _MAPEM_GPU(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, device, max_saves, show_logs=True)
|
|
46
|
+
else:
|
|
47
|
+
return _MAPEM_CPU(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, max_saves, show_logs=True)
|
|
48
|
+
except Exception as e:
|
|
49
|
+
print(f"Error in MLEM: {type(e).__name__}: {e}")
|
|
50
|
+
return None, None
|
|
51
|
+
|
|
52
|
+
def MAPEM_STOP(
|
|
53
|
+
SMatrix,
|
|
54
|
+
y,
|
|
55
|
+
Omega,
|
|
56
|
+
beta,
|
|
57
|
+
delta=None,
|
|
58
|
+
gamma=None,
|
|
59
|
+
sigma=None,
|
|
60
|
+
numIterations=100,
|
|
61
|
+
isSavingEachIteration=True,
|
|
62
|
+
withTumor=True,
|
|
63
|
+
device=None,
|
|
64
|
+
max_saves=5000,
|
|
65
|
+
show_logs=True):
|
|
66
|
+
"""
|
|
67
|
+
This method implements the MAPEM_STOP algorithm using either CPU or single-GPU PyTorch acceleration.
|
|
68
|
+
Multi-GPU and Multi-CPU modes are not implemented for this algorithm.
|
|
69
|
+
"""
|
|
70
|
+
try:
|
|
71
|
+
tumor_str = "WITH" if withTumor else "WITHOUT"
|
|
72
|
+
# Auto-select device and method
|
|
73
|
+
if device is None:
|
|
74
|
+
if torch.cuda.is_available() and check_gpu_memory(config.select_best_gpu(), calculate_memory_requirement(SMatrix, y), show_logs=show_logs):
|
|
75
|
+
device = torch.device(f"cuda:{config.select_best_gpu()}")
|
|
76
|
+
use_gpu = True
|
|
77
|
+
else:
|
|
78
|
+
device = torch.device("cpu")
|
|
79
|
+
use_gpu = False
|
|
80
|
+
else:
|
|
81
|
+
use_gpu = device.type == "cuda"
|
|
82
|
+
# Dispatch to the appropriate implementation
|
|
83
|
+
if use_gpu:
|
|
84
|
+
return _MAPEM_GPU_STOP(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, device, max_saves, show_logs=True)
|
|
85
|
+
else:
|
|
86
|
+
return _MAPEM_CPU_STOP(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, max_saves, show_logs=True)
|
|
87
|
+
except Exception as e:
|
|
88
|
+
print(f"Error in MLEM: {type(e).__name__}: {e}")
|
|
89
|
+
return None, None
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _MAPEM_CPU_STOP(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, max_saves, show_logs=True):
|
|
93
|
+
"""
|
|
94
|
+
MAPEM version CPU simple - sans GPU - torch uniquement
|
|
95
|
+
"""
|
|
96
|
+
try:
|
|
97
|
+
if not isinstance(Omega, PotentialType):
|
|
98
|
+
raise TypeError(f"Omega must be of type PotentialType, got {type(Omega)}")
|
|
99
|
+
if Omega == PotentialType.HUBER_PIECEWISE:
|
|
100
|
+
if delta is None:
|
|
101
|
+
raise ValueError("delta must be specified for HUBER_PIECEWISE potential type.")
|
|
102
|
+
if beta is None:
|
|
103
|
+
raise ValueError("beta must be specified for HUBER_PIECEWISE potential type.")
|
|
104
|
+
elif Omega == PotentialType.RELATIVE_DIFFERENCE:
|
|
105
|
+
if gamma is None:
|
|
106
|
+
raise ValueError("gamma must be specified for RELATIVE_DIFFERENCE potential type.")
|
|
107
|
+
if beta is None:
|
|
108
|
+
raise ValueError("beta must be specified for RELATIVE_DIFFERENCE potential type.")
|
|
109
|
+
elif Omega == PotentialType.QUADRATIC:
|
|
110
|
+
if sigma is None:
|
|
111
|
+
raise ValueError("sigma must be specified for QUADRATIC potential type.")
|
|
112
|
+
if beta is None:
|
|
113
|
+
raise ValueError("beta must be specified for QUADRATIC potential type.")
|
|
114
|
+
else:
|
|
115
|
+
raise ValueError(f"Unknown potential type: {Omega}")
|
|
116
|
+
|
|
117
|
+
SMatrix = torch.tensor(SMatrix, dtype=torch.float32)
|
|
118
|
+
y_tensor = torch.tensor(y, dtype=torch.float32)
|
|
119
|
+
T, Z, X, N = SMatrix.shape
|
|
120
|
+
A_flat = SMatrix.permute(0, 3, 1, 2).reshape(T * N, Z * X)
|
|
121
|
+
y_flat = y_tensor.reshape(-1)
|
|
122
|
+
I_0 = torch.ones((Z, X), dtype=torch.float32)
|
|
123
|
+
theta_list = [I_0]
|
|
124
|
+
results = [I_0.numpy()]
|
|
125
|
+
saved_indices = [0]
|
|
126
|
+
normalization_factor = SMatrix.sum(dim=(0, 3)).reshape(-1)
|
|
127
|
+
adj_index, adj_values = _build_adjacency_sparse(Z, X)
|
|
128
|
+
|
|
129
|
+
# Calculate save indices
|
|
130
|
+
if numIterations <= max_saves:
|
|
131
|
+
save_indices = list(range(numIterations))
|
|
132
|
+
else:
|
|
133
|
+
step = numIterations // max_saves
|
|
134
|
+
save_indices = list(range(0, numIterations, step))
|
|
135
|
+
if save_indices[-1] != numIterations - 1:
|
|
136
|
+
save_indices.append(numIterations - 1)
|
|
137
|
+
|
|
138
|
+
if Omega == PotentialType.HUBER_PIECEWISE:
|
|
139
|
+
description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse HUBER β:{beta:.4f}, δ:{delta:.4f}) + STOP condition (penalized log-likelihood) ---- {tumor_str} TUMOR ---- processing on single CPU ----"
|
|
140
|
+
elif Omega == PotentialType.RELATIVE_DIFFERENCE:
|
|
141
|
+
description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse RD β:{beta:.4f}, γ:{gamma:.4f}) + STOP condition (penalized log-likelihood) ---- {tumor_str} TUMOR ---- processing on single CPU ----"
|
|
142
|
+
elif Omega == PotentialType.QUADRATIC:
|
|
143
|
+
description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse QUADRATIC β:{beta:.4f}, σ:{sigma:.4f}) + STOP condition (penalized log-likelihood) ---- {tumor_str} TUMOR ---- processing on single CPU ----"
|
|
144
|
+
|
|
145
|
+
iterator = trange(numIterations, desc=description) if show_logs else range(numIterations)
|
|
146
|
+
for it in iterator:
|
|
147
|
+
theta_p = theta_list[-1]
|
|
148
|
+
theta_p_flat = theta_p.reshape(-1)
|
|
149
|
+
q_flat = A_flat @ theta_p_flat
|
|
150
|
+
e_flat = (y_flat - q_flat) / (q_flat + torch.finfo(torch.float32).tiny)
|
|
151
|
+
c_flat = A_flat.T @ e_flat
|
|
152
|
+
if Omega == PotentialType.HUBER_PIECEWISE:
|
|
153
|
+
grad_U, hess_U, U_value = _Omega_HUBER_PIECEWISE_CPU(theta_p_flat, adj_index, adj_values, delta=delta)
|
|
154
|
+
elif Omega == PotentialType.RELATIVE_DIFFERENCE:
|
|
155
|
+
grad_U, hess_U, U_value = _Omega_RELATIVE_DIFFERENCE_CPU(theta_p_flat, adj_index, adj_values, gamma=gamma)
|
|
156
|
+
elif Omega == PotentialType.QUADRATIC:
|
|
157
|
+
grad_U, hess_U, U_value = _Omega_QUADRATIC_CPU(theta_p_flat, adj_index, adj_values, sigma=sigma)
|
|
158
|
+
denom = normalization_factor + theta_p_flat * beta * hess_U
|
|
159
|
+
num = theta_p_flat * (c_flat - beta * grad_U)
|
|
160
|
+
theta_next_flat = theta_p_flat + num / (denom + torch.finfo(torch.float32).tiny)
|
|
161
|
+
theta_next_flat = torch.clamp(theta_next_flat, min=0)
|
|
162
|
+
theta_next = theta_next_flat.reshape(Z, X)
|
|
163
|
+
theta_list[-1] = theta_next
|
|
164
|
+
if isSavingEachIteration and it in save_indices:
|
|
165
|
+
results.append(theta_next.numpy())
|
|
166
|
+
saved_indices.append(it+1)
|
|
167
|
+
log_likelihood = (y_flat * torch.log(q_flat + 1e-8) - (q_flat + 1e-8)).sum()
|
|
168
|
+
penalized_log_likelihood = log_likelihood - beta * U_value
|
|
169
|
+
if (it + 1) % 100 == 0:
|
|
170
|
+
print(f"Iter {it+1}: logL={log_likelihood:.3e}, U={U_value:.3e}, penalized logL={penalized_log_likelihood:.3e}")
|
|
171
|
+
|
|
172
|
+
if isSavingEachIteration:
|
|
173
|
+
return results, saved_indices
|
|
174
|
+
else:
|
|
175
|
+
return results[-1], None
|
|
176
|
+
except Exception as e:
|
|
177
|
+
print(f"An error occurred in _MAPEM_CPU_STOP: {e}")
|
|
178
|
+
return None, None
|
|
179
|
+
|
|
180
|
+
def _MAPEM_GPU_STOP(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, device, max_saves, show_logs=True):
|
|
181
|
+
"""
|
|
182
|
+
Maximum A Posteriori (MAP) estimation for Bayesian reconstruction.
|
|
183
|
+
This method computes the MAP estimate of the parameters given the data.
|
|
184
|
+
"""
|
|
185
|
+
try:
|
|
186
|
+
if not isinstance(Omega, PotentialType):
|
|
187
|
+
raise TypeError(f"Omega must be of type PotentialType, got {type(Omega)}")
|
|
188
|
+
if Omega == PotentialType.HUBER_PIECEWISE:
|
|
189
|
+
if delta is None:
|
|
190
|
+
raise ValueError("delta must be specified for HUBER_PIECEWISE potential type.")
|
|
191
|
+
if beta is None:
|
|
192
|
+
raise ValueError("beta must be specified for HUBER_PIECEWISE potential type.")
|
|
193
|
+
elif Omega == PotentialType.RELATIVE_DIFFERENCE:
|
|
194
|
+
if gamma is None:
|
|
195
|
+
raise ValueError("gamma must be specified for RELATIVE_DIFFERENCE potential type.")
|
|
196
|
+
if beta is None:
|
|
197
|
+
raise ValueError("beta must be specified for RELATIVE_DIFFERENCE potential type.")
|
|
198
|
+
elif Omega == PotentialType.QUADRATIC:
|
|
199
|
+
if sigma is None:
|
|
200
|
+
raise ValueError("sigma must be specified for QUADRATIC potential type.")
|
|
201
|
+
if beta is None:
|
|
202
|
+
raise ValueError("beta must be specified for QUADRATIC potential type.")
|
|
203
|
+
else:
|
|
204
|
+
raise ValueError(f"Unknown potential type: {Omega}")
|
|
205
|
+
|
|
206
|
+
A_matrix_torch = torch.tensor(SMatrix, dtype=torch.float32).to(device)
|
|
207
|
+
y_torch = torch.tensor(y, dtype=torch.float32).to(device)
|
|
208
|
+
T, Z, X, N = SMatrix.shape
|
|
209
|
+
J = Z * X
|
|
210
|
+
A_flat = A_matrix_torch.permute(0, 3, 1, 2).reshape(T * N, Z * X)
|
|
211
|
+
y_flat = y_torch.reshape(-1)
|
|
212
|
+
I_0 = torch.ones((Z, X), dtype=torch.float32, device=device)
|
|
213
|
+
matrix_theta_torch = [I_0]
|
|
214
|
+
matrix_theta_from_gpu_MAPEM = [I_0.cpu().numpy()]
|
|
215
|
+
saved_indices = [0]
|
|
216
|
+
normalization_factor = A_matrix_torch.sum(dim=(0, 3))
|
|
217
|
+
normalization_factor_flat = normalization_factor.reshape(-1)
|
|
218
|
+
previous = -np.inf
|
|
219
|
+
nb_false_successive = 0
|
|
220
|
+
adj_index, adj_values = _build_adjacency_sparse(Z, X, device=device)
|
|
221
|
+
|
|
222
|
+
# Calculate save indices
|
|
223
|
+
if numIterations <= max_saves:
|
|
224
|
+
save_indices = list(range(numIterations))
|
|
225
|
+
else:
|
|
226
|
+
step = numIterations // max_saves
|
|
227
|
+
save_indices = list(range(0, numIterations, step))
|
|
228
|
+
if save_indices[-1] != numIterations - 1:
|
|
229
|
+
save_indices.append(numIterations - 1)
|
|
230
|
+
|
|
231
|
+
if Omega == PotentialType.HUBER_PIECEWISE:
|
|
232
|
+
description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse HUBER β:{beta:.4f}, δ:{delta:.4f}) + STOP condition (penalized log-likelihood) ---- {tumor_str} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
|
|
233
|
+
elif Omega == PotentialType.RELATIVE_DIFFERENCE:
|
|
234
|
+
description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse RD β:{beta:.4f}, γ:{gamma:.4f}) + STOP condition (penalized log-likelihood) ---- {tumor_str} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
|
|
235
|
+
elif Omega == PotentialType.QUADRATIC:
|
|
236
|
+
description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse QUADRATIC β:{beta:.4f}, σ:{sigma:.4f}) + STOP condition (penalized log-likelihood) ---- {tumor_str} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
|
|
237
|
+
|
|
238
|
+
iterator = trange(numIterations, desc=description) if show_logs else range(numIterations)
|
|
239
|
+
for it in iterator:
|
|
240
|
+
theta_p = matrix_theta_torch[-1]
|
|
241
|
+
theta_p_flat = theta_p.reshape(-1)
|
|
242
|
+
q_flat = A_flat @ theta_p_flat
|
|
243
|
+
e_flat = (y_flat - q_flat) / (q_flat + torch.finfo(torch.float32).tiny)
|
|
244
|
+
c_flat = A_flat.T @ e_flat
|
|
245
|
+
if Omega == PotentialType.HUBER_PIECEWISE:
|
|
246
|
+
grad_U, hess_U, U_value = _Omega_HUBER_PIECEWISE_GPU(theta_p_flat, adj_index, adj_values, device=device, delta=delta)
|
|
247
|
+
elif Omega == PotentialType.RELATIVE_DIFFERENCE:
|
|
248
|
+
grad_U, hess_U, U_value = _Omega_RELATIVE_DIFFERENCE_GPU(theta_p_flat, adj_index, adj_values, device=device, gamma=gamma)
|
|
249
|
+
elif Omega == PotentialType.QUADRATIC:
|
|
250
|
+
grad_U, hess_U, U_value = _Omega_QUADRATIC_GPU(theta_p_flat, adj_index, adj_values, device=device, sigma=sigma)
|
|
251
|
+
else:
|
|
252
|
+
raise ValueError(f"Unknown potential type: {Omega}")
|
|
253
|
+
denom = normalization_factor_flat + theta_p_flat * beta * hess_U
|
|
254
|
+
num = theta_p_flat * (c_flat - beta * grad_U)
|
|
255
|
+
theta_p_plus_1_flat = theta_p_flat + num / (denom + torch.finfo(torch.float32).tiny)
|
|
256
|
+
theta_p_plus_1_flat = torch.clamp(theta_p_plus_1_flat, min=0)
|
|
257
|
+
theta_next = theta_p_plus_1_flat.reshape(Z, X)
|
|
258
|
+
matrix_theta_torch[-1] = theta_next
|
|
259
|
+
if isSavingEachIteration and it in save_indices:
|
|
260
|
+
matrix_theta_from_gpu_MAPEM.append(theta_next.cpu().numpy())
|
|
261
|
+
saved_indices.append(it+1)
|
|
262
|
+
log_likelihood = (y_flat * (torch.log(q_flat + torch.finfo(torch.float32).tiny)) - (q_flat + torch.finfo(torch.float32).tiny)).sum()
|
|
263
|
+
penalized_log_likelihood = log_likelihood - beta * U_value
|
|
264
|
+
if it == 0 or (it + 1) % 100 == 0:
|
|
265
|
+
current = penalized_log_likelihood.item()
|
|
266
|
+
if current <= previous:
|
|
267
|
+
nb_false_successive += 1
|
|
268
|
+
else:
|
|
269
|
+
nb_false_successive = 0
|
|
270
|
+
print(f"Iter {it + 1}: lnL without term ln(m_i !) inside={log_likelihood.item():.8e}, Gibbs energy function U={U_value.item():.4e}, penalized lnL without term ln(m_i !) inside={penalized_log_likelihood.item():.8e}, p lnL (current {current:.8e} - previous {previous:.8e} > 0)={(current - previous > 0)}, nb_false_successive={nb_false_successive}")
|
|
271
|
+
previous = current
|
|
272
|
+
|
|
273
|
+
del A_matrix_torch, y_torch, A_flat, y_flat, I_0, normalization_factor, normalization_factor_flat
|
|
274
|
+
torch.cuda.empty_cache()
|
|
275
|
+
if isSavingEachIteration:
|
|
276
|
+
return matrix_theta_from_gpu_MAPEM, saved_indices
|
|
277
|
+
else:
|
|
278
|
+
return matrix_theta_from_gpu_MAPEM[-1], None
|
|
279
|
+
except Exception as e:
|
|
280
|
+
print(f"An error occurred in _MAPEM_GPU_STOP: {e}")
|
|
281
|
+
del A_matrix_torch, y_torch, A_flat, y_flat, I_0, normalization_factor, normalization_factor_flat
|
|
282
|
+
torch.cuda.empty_cache()
|
|
283
|
+
return None, None
|
|
284
|
+
|
|
285
|
+
def _MAPEM_CPU(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, max_saves, show_logs=True):
|
|
286
|
+
try:
|
|
287
|
+
if not isinstance(Omega, PotentialType):
|
|
288
|
+
raise TypeError(f"Omega must be of type PotentialType, got {type(Omega)}")
|
|
289
|
+
if Omega == PotentialType.HUBER_PIECEWISE:
|
|
290
|
+
if delta is None:
|
|
291
|
+
raise ValueError("delta must be specified for HUBER_PIECEWISE potential type.")
|
|
292
|
+
if beta is None:
|
|
293
|
+
raise ValueError("beta must be specified for HUBER_PIECEWISE potential type.")
|
|
294
|
+
elif Omega == PotentialType.RELATIVE_DIFFERENCE:
|
|
295
|
+
if gamma is None:
|
|
296
|
+
raise ValueError("gamma must be specified for RELATIVE_DIFFERENCE potential type.")
|
|
297
|
+
if beta is None:
|
|
298
|
+
raise ValueError("beta must be specified for RELATIVE_DIFFERENCE potential type.")
|
|
299
|
+
elif Omega == PotentialType.QUADRATIC:
|
|
300
|
+
if sigma is None:
|
|
301
|
+
raise ValueError("sigma must be specified for QUADRATIC potential type.")
|
|
302
|
+
if beta is None:
|
|
303
|
+
raise ValueError("beta must be specified for QUADRATIC potential type.")
|
|
304
|
+
else:
|
|
305
|
+
raise ValueError(f"Unknown potential type: {Omega}")
|
|
306
|
+
|
|
307
|
+
T, Z, X, N = SMatrix.shape
|
|
308
|
+
A_flat = np.transpose(SMatrix, (0, 3, 1, 2)).reshape(T * N, Z * X)
|
|
309
|
+
y_flat = y.reshape(-1)
|
|
310
|
+
theta_0 = np.ones((Z, X), dtype=np.float32)
|
|
311
|
+
matrix_theta_np = [theta_0]
|
|
312
|
+
I_reconMatrix = [theta_0.copy()]
|
|
313
|
+
saved_indices = [0]
|
|
314
|
+
normalization_factor = SMatrix.sum(axis=(0, 3))
|
|
315
|
+
normalization_factor_flat = normalization_factor.reshape(-1)
|
|
316
|
+
adj_index, adj_values = _build_adjacency_sparse(Z, X)
|
|
317
|
+
|
|
318
|
+
# Calculate save indices
|
|
319
|
+
if numIterations <= max_saves:
|
|
320
|
+
save_indices = list(range(numIterations))
|
|
321
|
+
else:
|
|
322
|
+
step = numIterations // max_saves
|
|
323
|
+
save_indices = list(range(0, numIterations, step))
|
|
324
|
+
if save_indices[-1] != numIterations - 1:
|
|
325
|
+
save_indices.append(numIterations - 1)
|
|
326
|
+
|
|
327
|
+
if Omega == PotentialType.HUBER_PIECEWISE:
|
|
328
|
+
description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse HUBER β:{beta:.4f}, δ:{delta:.4f}) ---- {tumor_str} TUMOR ---- processing on single CPU ----"
|
|
329
|
+
elif Omega == PotentialType.RELATIVE_DIFFERENCE:
|
|
330
|
+
description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse RD β:{beta:.4f}, γ:{gamma:.4f}) ---- {tumor_str} TUMOR ---- processing on single CPU ----"
|
|
331
|
+
elif Omega == PotentialType.QUADRATIC:
|
|
332
|
+
description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse QUADRATIC β:{beta:.4f}, σ:{sigma:.4f}) ---- {tumor_str} TUMOR ---- processing on single CPU ----"
|
|
333
|
+
|
|
334
|
+
iterator = trange(numIterations, desc=description) if show_logs else range(numIterations)
|
|
335
|
+
for it in iterator:
|
|
336
|
+
theta_p = matrix_theta_np[-1]
|
|
337
|
+
theta_p_flat = theta_p.reshape(-1)
|
|
338
|
+
q_flat = A_flat @ theta_p_flat
|
|
339
|
+
e_flat = (y_flat - q_flat) / (q_flat + np.finfo(np.float32).tiny)
|
|
340
|
+
c_flat = A_flat.T @ e_flat
|
|
341
|
+
if Omega == PotentialType.HUBER_PIECEWISE:
|
|
342
|
+
grad_U, hess_U, _ = _Omega_HUBER_PIECEWISE_CPU(theta_p_flat, adj_index, adj_values, delta=delta)
|
|
343
|
+
elif Omega == PotentialType.RELATIVE_DIFFERENCE:
|
|
344
|
+
grad_U, hess_U, _ = _Omega_RELATIVE_DIFFERENCE_CPU(theta_p_flat, adj_index, adj_values, gamma=gamma)
|
|
345
|
+
elif Omega == PotentialType.QUADRATIC:
|
|
346
|
+
grad_U, hess_U, _ = _Omega_QUADRATIC_CPU(theta_p_flat, adj_index, adj_values, sigma=sigma)
|
|
347
|
+
denom = normalization_factor_flat + theta_p_flat * beta * hess_U
|
|
348
|
+
num = theta_p_flat * (c_flat - beta * grad_U)
|
|
349
|
+
theta_p_plus_1_flat = theta_p_flat + num / (denom + np.finfo(np.float32).tiny)
|
|
350
|
+
theta_p_plus_1_flat = np.clip(theta_p_plus_1_flat, 0, None)
|
|
351
|
+
theta_next = theta_p_plus_1_flat.reshape(Z, X)
|
|
352
|
+
matrix_theta_np.append(theta_next)
|
|
353
|
+
if isSavingEachIteration and it in save_indices:
|
|
354
|
+
I_reconMatrix.append(theta_next.copy())
|
|
355
|
+
saved_indices.append(it+1)
|
|
356
|
+
|
|
357
|
+
if isSavingEachIteration:
|
|
358
|
+
return I_reconMatrix, saved_indices
|
|
359
|
+
else:
|
|
360
|
+
return I_reconMatrix[-1], None
|
|
361
|
+
except Exception as e:
|
|
362
|
+
print(f"An error occurred in _MAPEM_CPU: {e}")
|
|
363
|
+
return None, None
|
|
364
|
+
|
|
365
|
+
def _MAPEM_GPU(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, device, max_saves, show_logs=True):
|
|
366
|
+
"""
|
|
367
|
+
Maximum A Posteriori (MAP) estimation for Bayesian reconstruction using GPU.
|
|
368
|
+
This method computes the MAP estimate of the parameters given the data.
|
|
369
|
+
"""
|
|
370
|
+
try:
|
|
371
|
+
if not isinstance(Omega, PotentialType):
|
|
372
|
+
raise TypeError(f"Omega must be of type PotentialType, got {type(Omega)}")
|
|
373
|
+
if Omega == PotentialType.HUBER_PIECEWISE:
|
|
374
|
+
if delta is None:
|
|
375
|
+
raise ValueError("delta must be specified for HUBER_PIECEWISE potential type.")
|
|
376
|
+
if beta is None:
|
|
377
|
+
raise ValueError("beta must be specified for HUBER_PIECEWISE potential type.")
|
|
378
|
+
elif Omega == PotentialType.RELATIVE_DIFFERENCE:
|
|
379
|
+
if gamma is None:
|
|
380
|
+
raise ValueError("gamma must be specified for RELATIVE_DIFFERENCE potential type.")
|
|
381
|
+
if beta is None:
|
|
382
|
+
raise ValueError("beta must be specified for RELATIVE_DIFFERENCE potential type.")
|
|
383
|
+
elif Omega == PotentialType.QUADRATIC:
|
|
384
|
+
if sigma is None:
|
|
385
|
+
raise ValueError("sigma must be specified for QUADRATIC potential type.")
|
|
386
|
+
if beta is None:
|
|
387
|
+
raise ValueError("beta must be specified for QUADRATIC potential type.")
|
|
388
|
+
else:
|
|
389
|
+
raise ValueError(f"Unknown potential type: {Omega}")
|
|
390
|
+
|
|
391
|
+
A_matrix_torch = torch.tensor(SMatrix, dtype=torch.float32).to(device)
|
|
392
|
+
y_torch = torch.tensor(y, dtype=torch.float32).to(device)
|
|
393
|
+
T, Z, X, N = SMatrix.shape
|
|
394
|
+
J = Z * X
|
|
395
|
+
A_flat = A_matrix_torch.permute(0, 3, 1, 2).reshape(T * N, Z * X)
|
|
396
|
+
y_flat = y_torch.reshape(-1)
|
|
397
|
+
theta_0 = torch.ones((Z, X), dtype=torch.float32, device=device)
|
|
398
|
+
matrix_theta_torch = [theta_0]
|
|
399
|
+
I_reconMatrix = [theta_0.cpu().numpy()]
|
|
400
|
+
saved_indices = [0]
|
|
401
|
+
normalization_factor = A_matrix_torch.sum(dim=(0, 3))
|
|
402
|
+
normalization_factor_flat = normalization_factor.reshape(-1)
|
|
403
|
+
adj_index, adj_values = _build_adjacency_sparse(Z, X, device=device)
|
|
404
|
+
|
|
405
|
+
# Calculate save indices
|
|
406
|
+
if numIterations <= max_saves:
|
|
407
|
+
save_indices = list(range(numIterations))
|
|
408
|
+
else:
|
|
409
|
+
step = numIterations // max_saves
|
|
410
|
+
save_indices = list(range(0, numIterations, step))
|
|
411
|
+
if save_indices[-1] != numIterations - 1:
|
|
412
|
+
save_indices.append(numIterations - 1)
|
|
413
|
+
|
|
414
|
+
if Omega == PotentialType.HUBER_PIECEWISE:
|
|
415
|
+
description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse HUBER β:{beta:.4f}, δ:{delta:.4f}) ---- {tumor_str} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
|
|
416
|
+
elif Omega == PotentialType.RELATIVE_DIFFERENCE:
|
|
417
|
+
description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse RD β:{beta:.4f}, γ:{gamma:.4f}) ---- {tumor_str} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
|
|
418
|
+
elif Omega == PotentialType.QUADRATIC:
|
|
419
|
+
description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse QUADRATIC σ:{sigma:.4f}) ---- {tumor_str} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
|
|
420
|
+
|
|
421
|
+
iterator = trange(numIterations, desc=description) if show_logs else range(numIterations)
|
|
422
|
+
for it in iterator:
|
|
423
|
+
theta_p = matrix_theta_torch[-1]
|
|
424
|
+
theta_p_flat = theta_p.reshape(-1)
|
|
425
|
+
q_flat = A_flat @ theta_p_flat
|
|
426
|
+
e_flat = (y_flat - q_flat) / (q_flat + torch.finfo(torch.float32).tiny)
|
|
427
|
+
c_flat = A_flat.T @ e_flat
|
|
428
|
+
if Omega == PotentialType.HUBER_PIECEWISE:
|
|
429
|
+
grad_U, hess_U, _ = _Omega_HUBER_PIECEWISE_GPU(theta_p_flat, adj_index, adj_values, device=device, delta=delta)
|
|
430
|
+
elif Omega == PotentialType.RELATIVE_DIFFERENCE:
|
|
431
|
+
grad_U, hess_U, _ = _Omega_RELATIVE_DIFFERENCE_GPU(theta_p_flat, adj_index, adj_values, device=device, gamma=gamma)
|
|
432
|
+
elif Omega == PotentialType.QUADRATIC:
|
|
433
|
+
grad_U, hess_U, _ = _Omega_QUADRATIC_GPU(theta_p_flat, adj_index, adj_values, device=device, sigma=sigma)
|
|
434
|
+
else:
|
|
435
|
+
raise ValueError(f"Unknown potential type: {Omega}")
|
|
436
|
+
denom = normalization_factor_flat + theta_p_flat * beta * hess_U
|
|
437
|
+
num = theta_p_flat * (c_flat - beta * grad_U)
|
|
438
|
+
theta_p_plus_1_flat = theta_p_flat + num / (denom + torch.finfo(torch.float32).tiny)
|
|
439
|
+
theta_p_plus_1_flat = torch.clamp(theta_p_plus_1_flat, min=0)
|
|
440
|
+
theta_next = theta_p_plus_1_flat.reshape(Z, X)
|
|
441
|
+
matrix_theta_torch.append(theta_next)
|
|
442
|
+
if isSavingEachIteration and it in save_indices:
|
|
443
|
+
I_reconMatrix.append(theta_next.cpu().numpy())
|
|
444
|
+
saved_indices.append(it+1)
|
|
445
|
+
|
|
446
|
+
del A_matrix_torch, y_torch, A_flat, y_flat, theta_0, normalization_factor, normalization_factor_flat
|
|
447
|
+
torch.cuda.empty_cache()
|
|
448
|
+
if isSavingEachIteration:
|
|
449
|
+
return I_reconMatrix, saved_indices
|
|
450
|
+
else:
|
|
451
|
+
return I_reconMatrix[-1], None
|
|
452
|
+
except Exception as e:
|
|
453
|
+
print(f"An error occurred in _MAPEM_GPU: {e}")
|
|
454
|
+
del A_matrix_torch, y_torch, A_flat, y_flat, theta_0, normalization_factor, normalization_factor_flat
|
|
455
|
+
torch.cuda.empty_cache()
|
|
456
|
+
return None, None
|