Симуляция систолического массива в Python

Я пытаюсь смоделировать структуру систолического массива - все, что я узнал из этих слайдов: http://web.cecs.pdx.edu/~mperkows/temp/May22/0020.Matrix-multiplication-systolic.pdf - для умножения матриц в среде Python. Неотъемлемой частью систолического массива является то, что поток данных между PE совпадает с любым умножением или сложением, которое происходит на каком-либо одном узле. У меня возникают трудности с предположением, как именно реализовать такую ​​параллельную процедуру в Python. В частности, я надеюсь лучше понять вычислительный подход для подачи элементов матриц для умножения в систолический массив каскадным способом, в то же время позволяя этим элементам распространяться через массив одновременно.

Я начал писать некоторый код на python для умножения двух на три массива, но в конечном итоге я хочу смоделировать систолический массив любого размера для работы с матрицами любого размера a и b.

from threading import Thread
from collections import deque

vals_deque = deque(maxlen=9*2)#will hold the interconnections between nodes of the systolicarray
dump=deque(maxlen=9) # will be the output of the SystolicArray
prev_size = 0

def setupSystolicArray():
    global SystolicArray
    SystolicArray = [NodeSystolic(i,j) for i in range(3), for i in range(3)]

def spreadInputs(a,b):
    #needs some way to initially propagate the elements of a and b through the top and leftmost parts of the systolic array

    new = map(lambda x: x.start() , SystolicArray) #start all the nodes of the systolic array, they are waiting for an input

    #even if i found a way to put these inputs into the array at the start, I am not sure how to coordinate future inputs into the array in the cascading fashion described in the slides
    while(len(dump) != 9):
        if(len(vals_deque) != prev_size):

            vals = vals_deque[-1]
            row = vals['t'][0]
            col = vals['l'][0]
            a= vals['t'][1]
            b = vals['l'][1]
            # these if elif statements track whether the outputs are at the edge of the systolic array and can be removed
            if(row >= 3):
                dump.append(a)
            elif(col >= 3):
                dump.append(b)
            else:
                #something is wrong with the logic here
                SystolicArray[t][l-1].update(a,b)
                SystolicArray[t-1][l].update(a,b)   

class NodeSystolic:
    def __init__(self,row, col):
        self.row = row
        self.col = col
        self.currval = 0
        self.up = False
        self.ain = 0#coming in from the top
        self.bin = 0#coming in from the side

    def start(self):
        Thread(target=self.continuous, args = ()).start()

    def continuous(self):
        while True:
            if(self.up = True):
                self.currval = self.ain*self.bin
                self.up = False
                self.passon(self.ain, self.bin)
            else:
                pass

    def update(self, left, top):
        self.up = True
        self.ain = top
        self.bin = left

    def passon(self, t,l):
        #this will passon the inputs this node has received onto the next nodes
        vals_deque.append([{'t': [self.row+ 1, self.ain], 'l': [self.col + 1, self.bin]}])

    def returnValue(self):
        return self.currval


def main():
    a = np.array([
    [1,2,3],
    [4,5,6],
    [7,8,9],
    ])

    b = np.array([
    [1,2,3],
    [4,5,6],
    [7,8,9]
    ])

    setupSystolicArray()
    spreadInputs(a,b)

Приведенный выше код не работает и по-прежнему содержит много ошибок. Я надеялся, что кто-нибудь подскажет мне, как улучшить код, или есть ли гораздо более простой способ моделирования параллельных процедур систолического массива с асинхронными свойствами в Python, поэтому с очень большими размерами систолического массива я выиграл ' не нужно беспокоиться о создании слишком большого количества потоков (узлов).

1 ответ

Решение

Интересно подумать об имитации систолического массива в Python, но я думаю, что в этом есть некоторые существенные трудности в соответствии с тем, что вы набросали выше.

Наиболее важно то, что существуют проблемы с ограниченным объемом истинного параллелизма в Python, вызванные глобальной блокировкой интерпретатора. Это означает, что вы не получите никакого существенного параллелизма для задач с ограниченным количеством вычислений, и его потоки, вероятно, лучше всего подходят для обработки задач с ограниченным вводом / выводом, таких как веб-запросы или обращения к файловой системе. Ближайший Python может добраться до этого, вероятно, через многопроцессорный модуль, но для этого потребуется отдельный процесс для каждого узла.

Во-вторых, даже если бы вы собирались получить параллелизм в числовых операциях в вашем систолическом массиве, вам нужно было бы иметь некоторые механизмы блокировки, чтобы позволить различным потокам обмениваться данными (или сообщениями) без повреждения памяти друг друга, когда они пытаются читать и записывать данные одновременно.

Что касается структур данных в вашем примере, я думаю, что вам лучше иметь каждый узел в систолическом массиве, имеющий ссылку на его восходящие узлы, а не знать, что он находится в определенном месте в сетке NxM. Я не думаю, что есть какая-то причина, почему систолический массив должен быть прямоугольной сеткой, и любой из Направленного ациклического графа (DAG) все еще будет иметь потенциал для эффективных распределенных вычислений.

В целом, я ожидаю, что вычислительные затраты на выполнение этого моделирования в Python будут огромными по сравнению с тем, что может быть достигнуто с помощью языков более низкого уровня, таких как Scala или C++. Даже тогда, если каждый узел в систолическом массиве не выполняет много вычислений (то есть намного больше, чем несколько множителей), издержки обмена сообщениями между узлами будут существенными. Итак, я предполагаю, что ваша симуляция в основном предназначена для понимания потоков данных и высокоуровневого поведения массива, а не для того, чтобы приблизиться к тому, что может быть обеспечено специальным аппаратным обеспечением DSP (Digital Signal Processing). Если это так, то у меня будет соблазн просто обойтись без потоков и использовать централизованную очередь сообщений, в которую все узлы отправляют сообщения, доставляемые с помощью глобального механизма распространения сообщений.

Другие вопросы по тегам