Параллельное программирование вложенного цикла for в Python с использованием PyCuda (или еще?) - PullRequest
0 голосов
/ 15 мая 2018

Часть моей функции Python выглядит следующим образом:

for i in range(0, len(longitude_aq)):
    center = Coordinates(latitude_aq[i], longitude_aq[i])
    currentAq = aq[i, :]
    for j in range(0, len(longitude_meo)):
        currentMeo = meo[j, :]
        grid_point = Coordinates(latitude_meo[j], longitude_meo[j])
        if is_in_circle(center, RADIUS, grid_point):
            if currentAq[TIME_AQ] == currentMeo[TIME_MEO]:
                humidity += currentMeo[HUMIDITY_MEO]
                pressure += currentMeo[PRESSURE_MEO]
                temperature += currentMeo[TEMPERATURE_MEO]
                wind_speed += currentMeo[WIND_SPEED_MEO]
                wind_direction += currentMeo[WIND_DIRECTION_MEO]
                count += 1.0

    if count != 0.0:
        final_tmp[i, HUMIDITY_FINAL] = humidity/count
        final_tmp[i, PRESSURE_FINAL] = pressure/count
        final_tmp[i, TEMPERATURE_FINAL] = temperature/count
        final_tmp[i, WIND_SPEED_FINAL] = wind_speed/count
        final_tmp[i, WIND_DIRECTION_FINAL] = wind_direction/count

    humidity, pressure, temperature, wind_speed, wind_direction, count = 0.0, 0.0, 0.0, 0.0, 0.0, 0.0

final.loc[:, :] = final_tmp[:, :]

Проблема: len(longitude_aq) составляет ок.320k и len(longitude_meo) это 7 миллионов.Что приводит к тому, что этот код приближается к 2100 миллиардам итераций ...

Я должен выполнить итерацию по одному файлу (longitude_aq один), а затем вычислить некоторое среднее значение, повторяя по второму файлу (* 1011)* один) учитывая некоторые особенности, извлеченные из первого файла.

Не похоже, что я могу действовать иначе.

Возможное решение: параллельное программирование.Мой университет позволяет мне получить доступ к их HPC.У них есть несколько узлов + несколько доступных графических процессоров (список здесь для графических процессоров и здесь для процессоров)

Цель: Не имея опыта работы сПрограммируя CUDA на Python, мне интересно, что было бы самым простым способом преобразовать мой код во что-то, запускаемое HPC, чтобы время вычислений резко сократилось.

1 Ответ

0 голосов
/ 15 мая 2018

Извините, чтение может стать трудным для чтения, но реальность жестока, и многие энтузиасты могут легко испортить man*months из " кодирования " усилий в преимущественно априори проигранная война .Лучше тщательно переоценить все априорные известные КОНС / ПРОФИ любых планов реинжиниринга, прежде чем ослепнуть, потратить один человек * день в принципиально неправильном направлении.

Скорее всего, я бы не стал его публиковатьздесь, если бы я не сталкивался с Проектом, где академики высшего уровня потратили десятки man*years, да, более года с командой из 12+, для «производства» обработки обработки~ 26 [hr], который можно было воспроизвести в меньше, чем ~ 15 [min] (и намного дешевле при затратах на инфраструктуру HPC / GPU), если он был разработан с использованием надлежащего (без ущерба для производительности оборудования)методы проектирования ...

Не похоже, что я могу действовать иначе.

Ну, на самом деле довольно сложноскажи, если не невозможно:

В твоем посте, похоже, предполагается несколько кардинальных вещей, которые могут не принести реальной выгоды от переноса набросанной идеи на действительно профессиональную инфраструктуру HPC / GPU.

Возможное решение: параллельное программирование

Проще сказать / напечатать его, чем на самом деле.

A-wish-to-run-in-true- [PARALLEL] планирование процессов остается лишь желанием и (поверьте мне, или Джину Амдалю, или другим ветеранам C / S или нет) действительно трудная перепроектирование процесса, если вашкод должен быть значительно лучше, чем в чистом [SERIAL] потоке выполнения кода (как указано выше)

1) в чистом виде [SERIAL] банка fileIO (почти) убить игру:

неопубликованная часть о чистых - [SERIAL] файл -доступы (два файла с данными-баллы) ... любой fileIO по своей природе является самым дорогим ресурсом, и, кроме умного реинжиниринга, является чисто [SERIAL] (в лучшем случае универсальным, но все же) (пере) чтениемпоследовательно, поэтому не ожидайте никакого гигантского скачка где-либо далеко от этого в переработанном коде.Это будет всегда самый медленный и всегда дорогой этап.

2) затраты / выгоды могут принести вам ОПЛАТУ-БОЛЬШЕ-ЧЕМ-ВАС-ПОЛУЧИТЬ

Эта часть действительно ваша худшаявраг: если общая сумма ваших усилий превышает сумму чистых выгод, GPU не добавит никакой добавленной стоимости вообще или ее будет недостаточно, чтобы покрыть ваши дополнительные расходы.

Почему?

Графические процессоры - это SIMD-устройства, которые отлично подходят для использования маскировки задержки на обширной области повторяющегося одного и того же блока SMX-инструкций, для которого требуется определенный " weight"- of -" nice"- математика должна происходить локально, если она должна показать какое-либо ускорение обработки по сравнению с другими стратегиями реализации задач - устройствами с графическим процессором (не геймерскими, ноHPC, которые не все карты в классе, они?) лучше всего подходят для действительно небольших областей локальности данных (матричные операции с ядром, с очень плотной, лучше всего очень маленькой SMX-локальной "RAM"след такого плотного ядра<< ~ 100 [kB] по состоянию на 2018 / Q2).

Ваша «вычислительная» часть кода имеет НУЛЕВОЕ ИСПОЛЬЗОВАНИЕ любого отдельного элемента данных, который (довольно дорого) был извлечен из исходного статического хранилища,так что почти все преимущества, для которых была изобретена артиллерия GPU / SMX / SIMD, НЕ ИСПОЛЬЗУЕТСЯ ВСЕ , и вы получаете ОТРИЦАТЕЛЬНУЮ чистую выгоду от попытки загрузить такой код на такой разнородныйNUMA сложное) распределенные вычисления (да, каждое GPU-устройство довольно «далеко», «дорого» (если ваш код не будет использовать свои SMX-ресурсы до тех пор, пока из GPU-кремния… почти не будет дымить) и «удаленный»"асинхронно управляемый узел распределенных вычислений в вашей глобальной вычислительной стратегии).

Любое первое ветвление кода GPU будет чрезвычайно затратным с точки зрения затрат на выполнение SIMD, поэтому ваш код с большим if синтаксически справедливым, но с точки зрения производительности почти убийцейигра:

for i in range( 0,
                len( longitude_aq )
                ): #______________________________________ITERATOR #1 ( SEQ-of-I-s )
    currentAq =                        aq[i, :]           # .SET
    center    = Coordinates(  latitude_aq[i],             # .SET
                             longitude_aq[i]
                             ) #          |
    #                                     +-------------> # EASY2VECTORISE in [i]

    for j in range( 0,
                    len( longitude_meo )
                    ): #- - - - - - - - - - - - - - - - - ITERATOR #2 ( SEQ-of-J-s )
        currentMeo =                        meo[j, :]     # .SET
        grid_point = Coordinates(  latitude_meo[j],       # .SET
                                  longitude_meo[j]
                                  ) #           |
        #                                       +-------> # EASY2VECTORISE in [j]
        if is_in_circle( center,
                         RADIUS,
                         grid_point
                         ): # /\/\/\/\/\/\/\/\/\/\/\/\/\/ IF-ed SIMD-KILLER #1
            if (   currentAq[TIME_AQ]
               == currentMeo[TIME_MEO]
                  ): # /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ IF-ed SIMD-KILLER #2
                humidity       += currentMeo[      HUMIDITY_MEO] # BEST PERF.
                pressure       += currentMeo[      PRESSURE_MEO] #   IF SMART
                temperature    += currentMeo[   TEMPERATURE_MEO] #   CURATED
                wind_speed     += currentMeo[    WIND_SPEED_MEO] #   AS NON
                wind_direction += currentMeo[WIND_DIRECTION_MEO] #   ATOMICS
                count          += 1.0

    if          count          != 0.0: # !!!!!!!!!!!!!!!!!! THIS NEVER HAPPENS
        # EXCEPT WHEN ZERO DATA-POINTS WERE AVAILABLE FOR THE i-TH ZONE,
        #        FILE DID NOT CONTAIN ANY SUCH,
        #        WHICH IS FAIR,
        #    BUT SUCH A BLOCK OUGHT NEVER HAVE STARTED ANY COMPUTING AT ALL
        #     IF ASPIRING FOR INDEED BEING LOADED
        #        ONTO AN HPC-GRADE COMPUTING INFRASTRUCTURE ( SPONSORED OR NOT )
        #
        final_tmp[i, HUMIDITY_FINAL]       = humidity       / count
        final_tmp[i, PRESSURE_FINAL]       = pressure       / count
        final_tmp[i, TEMPERATURE_FINAL]    = temperature    / count
        final_tmp[i, WIND_SPEED_FINAL]     = wind_speed     / count
        final_tmp[i, WIND_DIRECTION_FINAL] = wind_direction / count

Если мы опускаем итераторы в области всех перекрестков * - 1094 * -s и if -ed, то фактическое " полезно * 1097"* "- часть вычислений выполняет очень небольшое количество математики - задание содержит несколько SLOC-ов, в которых суммируются принципиально независимые значения (лучше всего избегать любого столкновения операции добавления, поэтому можно очень дешево обходиться независимо друг от друга, чтобыдругая (лучше всего с заранее извлеченными константами с опережением) менее чем за несколько [ns] ДА, вашей вычислительной нагрузки не требует ничего, кроме нескольких единиц [ns] для выполнения.

Проблема в умной инженерии потока данных (мне нравится называть это ГИДРАВЛИКА ДАННЫХ (как сделать еще более несжимаемымпоток данных в регистры { CPU | GPU | APU | *** } -процессора, чтобы получить их процессы))

Все остальное легко.Интеллектуальное решение HPC DATA-HYDRAULICS, как правило, не является.

Нет языка, никакие рамки не помогут вам в этом автоматически.Некоторые могут освободить некоторую часть разработки решения от ваших «ручных» усилий, некоторые не могут, некоторые даже могут испортить возможную производительность вычислений из-за «дешевых» ярлыков в их внутреннем конструктивном решении и сделанных компромиссах, которые не приносят пользу тому же самому.цель у вас - Производительность .


Лучший следующий шаг?

A) Постарайтесь лучше понять границы вычислительной инфраструктурывы рассчитываете использовать для своих экстенсивных (но не интенсивных (да, всего несколько SLOC на [i,j]), которые супервизоры HPC не любят видеть в своих дорогих высокопроизводительных HPC-ресурсах).

B) Если у вас проблемы со временем + численность персонала + финансовые ресурсы для реинжиниринга нисходящего DATA-HYDRAULICS решения, лучше переформулируйте ваш код, чтобы как минимум попасть ввекторизация, numpy / numba (не всегда numba получится значительно дальше, чем уже умный numpy -векторизованный код, но количественноive test расскажет факты за инцидент, а не в целом)

C) Если ваша вычислительная проблема, как ожидается, будет повторяться чаще, определенно оцените переработанный конвейер изранняя предварительная обработка для хранения данных (самая медленная часть обработки), где возможна предварительная обработка на основе потоков преимущественно статических значений, что может повлиять на результирующий поток DATA-HYDRAULICS (производительность) с предварительно вычисленными + умно выровненными значениями больше всего.Блок из нескольких ADD -с вниз по полосе не улучшится после нескольких [ns], как сообщалось выше, но медленный поток может прыгать на порядки величиныбыстрее, если перегруппироваться в разумный поток, используя все доступные, но "просто" - [CONCURRENT] -используемые ресурсы (любая попытка организовать True- [PARALLEL]*Планирование 1154 * - это полная ерунда, поскольку задача, в принципе, отнюдь не является проблемой планирования [PARALLEL], а представляет собой поток чистой [SERIAL] (повторной) обработки точек данных, где разумная, но "просто"«- [CONCURRENT] переупорядочение обработки может помочь сократить результирующую длительность процесса).

...