优化简单的光子检测模拟
Optimizing a simple Photon Detection Simulation
我是一名尝试模拟光子检测的医学物理专业学生 - 我成功了(下图),但我想通过加快速度让它变得更好:目前 运行 需要 50 秒,我希望它能够运行 在那段时间的一小部分。我假设在 Python 方面更有知识的人可以优化它以在 10 秒内完成(不减少 num_photons_detected 值)。非常感谢您尝试这个小小的优化挑战。
from random import seed
from random import random
import random
import matplotlib.pyplot as plt
import numpy as np
rows, cols = (25, 25)
num_photons_detected = [10**3, 10**4, 10**5, 10**6, 10**7]
lesionPercentAboveNoiseLevel = [1, 0.20, 0.10, 0.05]
index_range = np.array([i for i in range(rows)])
for l in range(len(lesionPercentAboveNoiseLevel)):
pixels = np.array([[0.0 for i in range(cols)] for j in range(rows)])
for k in range(len(num_photons_detected)):
random.seed(a=None, version=2)
photons_random_pixel_choice = np.array([random.choice(index_range) for z in range(rows)])
counts = 0
while num_photons_detected[k] > counts:
for i in photons_random_pixel_choice:
photons_random_pixel_choice = np.array([random.choice(index_range) for z in range(rows)]) #further ensures random pixel selection
for j in photons_random_pixel_choice:
pixels[i,j] +=1
counts +=1
plt.imshow(pixels, cmap="gray") #in the resulting images/graphs, x is on the vertical and y on the horizontal
plt.show()
photons_random_pixel_choice = np.array([random.choice(index_range) for z in range(rows)])
看来这里的目标是:
- 使用 pre-made 整数序列,从 0 到 24(含)到 select 这些值之一。
- 在列表理解中重复该过程 25 次,以获得该范围内 25 个随机值的 Python 列表。
- 根据这些结果创建一维 Numpy 数组。
这非常缺少使用 Numpy 的要点。如果我们想要一个范围内的整数,那么我们可以直接请求那些。但更重要的是,我们应该在使用 Numpy 数据结构时尽可能让 Numpy 进行循环。这是支付给 read the documentation:
的地方
size: int or tuple of ints, optional
Output shape. If the given shape is, e.g., (m, n, k)
, then m * n * k
samples are drawn. Default is None
, in which case a single value is returned.
那么,直接做吧:photons_random_pixel_choice = random.integers(rows, size=(rows,))
.
我认为,除了效率问题之外,代码的一个问题是它 select 光子的位置并不是真正随机的。相反,它 selects 行号,然后对于每个 selected 行,它选择将在该行中观察到光子的列号。这样一来,如果一个行号没有被selected,那么那一行根本就没有光子,而如果同一行多次被selected,那么里面就会有很多光子.这在生成的图表中可见,这些图表具有清晰的浅色和深色行图案:
假设这是无意的,并且每个像素应该有相同的机会被 selected,这里是一个生成给定大小数组的函数,随机给定数量 select编辑像素:
import numpy as np
def generate_photons(rows, cols, num_photons):
rng = np.random.default_rng()
indices = rng.choice(rows*cols, num_photons)
np.add.at(pix:=np.zeros(rows*cols), indices, 1)
return pix.reshape(rows, cols)
您可以使用它来生成具有指定参数的图像。例如:
import matplotlib.pyplot as plt
pixels = generate_photons(rows=25, cols=25, num_photons=10**4)
plt.imshow(pixels, cmap="gray")
plt.show()
给出:
我是一名尝试模拟光子检测的医学物理专业学生 - 我成功了(下图),但我想通过加快速度让它变得更好:目前 运行 需要 50 秒,我希望它能够运行 在那段时间的一小部分。我假设在 Python 方面更有知识的人可以优化它以在 10 秒内完成(不减少 num_photons_detected 值)。非常感谢您尝试这个小小的优化挑战。
from random import seed
from random import random
import random
import matplotlib.pyplot as plt
import numpy as np
rows, cols = (25, 25)
num_photons_detected = [10**3, 10**4, 10**5, 10**6, 10**7]
lesionPercentAboveNoiseLevel = [1, 0.20, 0.10, 0.05]
index_range = np.array([i for i in range(rows)])
for l in range(len(lesionPercentAboveNoiseLevel)):
pixels = np.array([[0.0 for i in range(cols)] for j in range(rows)])
for k in range(len(num_photons_detected)):
random.seed(a=None, version=2)
photons_random_pixel_choice = np.array([random.choice(index_range) for z in range(rows)])
counts = 0
while num_photons_detected[k] > counts:
for i in photons_random_pixel_choice:
photons_random_pixel_choice = np.array([random.choice(index_range) for z in range(rows)]) #further ensures random pixel selection
for j in photons_random_pixel_choice:
pixels[i,j] +=1
counts +=1
plt.imshow(pixels, cmap="gray") #in the resulting images/graphs, x is on the vertical and y on the horizontal
plt.show()
photons_random_pixel_choice = np.array([random.choice(index_range) for z in range(rows)])
看来这里的目标是:
- 使用 pre-made 整数序列,从 0 到 24(含)到 select 这些值之一。
- 在列表理解中重复该过程 25 次,以获得该范围内 25 个随机值的 Python 列表。
- 根据这些结果创建一维 Numpy 数组。
这非常缺少使用 Numpy 的要点。如果我们想要一个范围内的整数,那么我们可以直接请求那些。但更重要的是,我们应该在使用 Numpy 数据结构时尽可能让 Numpy 进行循环。这是支付给 read the documentation:
的地方size: int or tuple of ints, optional
Output shape. If the given shape is, e.g.,
(m, n, k)
, thenm * n * k
samples are drawn. Default isNone
, in which case a single value is returned.
那么,直接做吧:photons_random_pixel_choice = random.integers(rows, size=(rows,))
.
我认为,除了效率问题之外,代码的一个问题是它 select 光子的位置并不是真正随机的。相反,它 selects 行号,然后对于每个 selected 行,它选择将在该行中观察到光子的列号。这样一来,如果一个行号没有被selected,那么那一行根本就没有光子,而如果同一行多次被selected,那么里面就会有很多光子.这在生成的图表中可见,这些图表具有清晰的浅色和深色行图案:
假设这是无意的,并且每个像素应该有相同的机会被 selected,这里是一个生成给定大小数组的函数,随机给定数量 select编辑像素:
import numpy as np
def generate_photons(rows, cols, num_photons):
rng = np.random.default_rng()
indices = rng.choice(rows*cols, num_photons)
np.add.at(pix:=np.zeros(rows*cols), indices, 1)
return pix.reshape(rows, cols)
您可以使用它来生成具有指定参数的图像。例如:
import matplotlib.pyplot as plt
pixels = generate_photons(rows=25, cols=25, num_photons=10**4)
plt.imshow(pixels, cmap="gray")
plt.show()
给出: