AOT-biomaps 2.9.138__py3-none-any.whl → 2.9.279__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.

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