优化简单的光子检测模拟

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)]) 
    

看来这里的目标是:

  1. 使用 pre-made 整数序列,从 0 到 24(含)到 select 这些值之一。
  2. 在列表理解中重复该过程 25 次,以获得该范围内 25 个随机值的 Python 列表。
  3. 根据这些结果创建一维 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()

给出: