代码之家  ›  专栏  ›  技术社区  ›  pythonic

邻域中不超过1个点的并行滤波方法

  •  2
  • pythonic  · 技术社区  · 7 年前

    我有一个空间 23x23x30 和每个立方体 1x1x1 表示一个点,其中一些 23x23x30 点由以下数字填充: -65 to -45 ,我想确保的任何给定区域中的数字不应超过1 5x5x30 如果在任何区域中有多个点 5x5x30 应消除数量最小的点。我使用嵌套 for 循环,但这是非常昂贵的操作。我想将此操作并行化。我有 n 核心和每个核心都有其自己的子区域的总区域 23x23x30 无任何重叠。我可以收集这些“子区域”,并构建 23x23x30 如上所述,所有内核都可以访问 23x23x30 同时,他们也有自己的“次区域”。我不确定python中是否有可用于此类操作的库。在我的应用程序中,8个进程将填充此 23x23x30 空间约为 3500 points,rite现在我正在对所有8个进程进行“过滤”操作(即复制工作)。这是对资源的浪费,因此我必须并行进行“过滤”,以便有效地使用可用资源。

    以下是序列号: self.tntatv_stdp_ids 是一本带键的字典 step1 , step2 ....最多 30 维度中的步骤, z . 这把钥匙有号码( 1 to 529 )该步骤中填充的点的数量。注意,在代码的串行实现中,在 z 维度来自 1至529 .

    self.cell_voltages 是一本带键的字典 步骤1 , 步骤二 ....最多 30 维度中的步骤, z . 每个键都给出了点中的数字。

         a_keys = self.tntatv_stdp_ids.keys()
    
        #Filter tentative neuron ids using suppression algo to come up with final stdp neuron ids. 
        for i in range(0,len(a_keys)):
            b_keys= list(set(a_keys) - set([a_keys[i]]))
            c_keys = self.tntatv_stdp_ids[a_keys[i]]
    
            for j in range(0,len(b_keys)):
                d_keys=self.tntatv_stdp_ids[b_keys[j]]
                for k in c_keys[:]:
                    key = k 
                    key_row= key/(image_size-kernel+1)
                    key_col = key%(image_size-kernel+1)
                    remove =0
                    for l in d_keys[:]:
                        target = l 
                        tar_row = target/(image_size-kernel+1)
                        tar_col = target%(image_size-kernel+1)
    
                        if(abs(key_row-tar_row) > kernel-1 and abs(key_col-tar_col) > kernel-1):
                            pass
                        else:
                            if(self.cell_voltages[a_keys[i]][key]>=self.cell_voltages[b_keys[j]][target]):
                                d_keys.remove(target)
                            else:
                                remove+=1
                    if(remove):
                        c_keys.remove(key)
    

    此操作结束时,如果 30 地区 23x23x1 ,每一个都有一个最终的赢家分数 30 23x23x1 可以通过查看 23x23x1 点数最多。通过这种方式,赢家的最大数量可以是 30 从中的所有点 23x23x30 ,每个 23x23x1 . 可以少于 30 此外,还取决于 23x23x30 首先填充点。

    1 回复  |  直到 7 年前
        1
  •  1
  •   TemporalWolf    7 年前

    此问题可能不需要并行化:

    # Generate a random array of appropriate size for testing
    super_array = [[[None for _ in range(30)] for _ in range(529)] for _ in range(529)]
    for _ in range(3500):
        super_array[random.randint(0, 528)][random.randint(0, 528)][random.randint(0,29)] = random.randint(-65, -45)
    

    第一步是构建填充节点的列表:

    filled = []
    for x in range(len(super_array)):
        for y in range(len(super_array[0])):
            for z in range(len(super_array[0][0])):
                if super_array[x][y][z] is not None:
                    filled.append((x, y, z, super_array[x][y][z]))
    

    然后,将列表从高到低排序:

    sfill = sorted(filled, key=lambda x: x[3], reverse=True)
    

    现在,生成一个阻塞网格:

    block_array = [[None for _ in range(529)] for _ in range(529)]
    

    并遍历该列表,在查找节点时封锁邻居并删除已占用邻居中的节点:

    for node in sfill: 
        x, y, z, _ = node
        if block_array[x][y] is not None:
            super_array[x][y][z] = None  # kill node if it's in the neighborhood of a larger node
        else: # Block their neighborhood
            for dx in range(5):
                for dy in range(5):
                    cx = x + dx - 2
                    cy = y + dy - 2
                    if 529 > cx >= 0 and 529 > cy >= 0:
                        block_array[cx][cy] = True
    

    一些注意事项:

    • 这将使用滑动邻域,因此它将检查以每个节点为中心的5x5。从高到低进行检查很重要,因为这样可以确保移除的节点之前不会强制移除其他节点。

    • 通过执行ranges而不是完整的529x529数组,您可以更高效地执行此操作,但邻域阻塞只需不到一秒钟的时间,从生成的数组到修剪的最终列表的整个过程只需1.2秒。

    • 只需在任何 z 堆栈如果大量节点最终具有相同的x,y值,这将减少必须排序的列表的大小。

    在23x23x30上,大约需要18ms,同样包括构建3d阵列的时间:

    timeit.timeit(prune_test, number=1000)
    17.61786985397339