#python #parallel-processing #montecarlo
#python #параллельная обработка #Монтекарло
Вопрос:
В настоящее время я реализую метод Монте-Карло для решения уравнения диффузии. Решение может быть выражено как математическое ожидание phi (W), где phi — функция (изменяется в соответствии с уравнением диффузии), а W — симметричное случайное блуждание, остановленное на границе области. Чтобы оценить функцию в точке x, мне нужно начинать каждое блуждание в ожидании от x.
Я хочу оценить функцию по большому количеству точек. Итак, это то, что я делаю:
- Я начинаю одновременно одно прохождение с каждой точки
- Я использую одни и те же шаги для каждой точки
- Как только каждое блуждание достигает границы, я останавливаюсь
- Я повторяю эти операции N раз, чтобы приблизить математическое ожидание по частоте в течение N симуляций.
Мой код (Python) выглядит так :
for k in range(N): #For each "walk"
step = 0
while not(every walk has reach the boundary):
map(update_walk,points) #update the walk starting from each x in points
incr(step)
Проблема в том, что это очень долго, поскольку N может быть большим, а также количество точек. Я ищу ЛЮБОЕ решение, которое поможет мне оптимизировать этот код.
Я думал о параллельной обработке (каждый обход независим) с помощью IPython, но мне это не удалось, потому что он находится внутри функции (он вернул ошибку типа
«не удалось запустить функцию ‘f’, потому что она не была найдена как ‘file.f’ » но ‘f’ определяется внутри file.big_f)
Комментарии:
1. Можете ли вы предоставить код update_walk? Это помогло бы увидеть работу, которую вы выполняете на каждом шаге. Является ли блуждание таким же простым, как /- random.uniform(-delta, delta)? Пока каждый не пройдет границу? Существует ли верхняя граница для шагов обхода, как в коде @mike-mckern? Кроме того, вы хотите продолжить обновление каждой точки или прекратить обновление по мере того, как каждая точка достигает границы?
Ответ №1:
Это один из немногих случаев, когда я могу не использовать параллельные вычисления. Я думаю, было бы быстрее просто использовать numpy
.
>>> import numpy as np
>>> def walk(x, n=100, box=.5, delta=.2):
... np.random.seed()
... w = np.cumsum(x np.random.uniform(-delta,delta,n))
... w = np.where(abs(w) > box)[0]
... return w[0] if len(w) else n
...
>>> pwalk = np.vectorize(walk)
>>> pwalk(np.zeros(10))
array([10, 25, 4, 5, 100, 6, 28, 6, 25, 23])
Я думаю, вы должны знать, как получить ожидаемое значение оттуда.
Вы также могли бы передать кортеж последнему аргументу np.random.uniform
, а затем не использовать np.vectorize
.
Конечно, если вы хотите использовать параллельные вычисления, то вы могли бы выбрать хорошую map
функцию и вызвать walk
из map
вместо использования vectorize
, как я сделал выше.
>>> from pathos.multiprocessing import ProcessingPool as Pool
>>> p = Pool(4)
>>> p.map(walk, [0]*10)
[8, 7, 39, 7, 36, 7, 22, 27, 18, 31]
Использование pathos
, поэтому карту можно легко вызвать из интерпретатора.
https://github.com/uqfoundation/pathos
Ответ №2:
Запуск вычисления в отдельном процессе (это то, что вы хотите, чтобы избежать GIL), вероятно, будет использовать модуль многопроцессорной обработки. Запуск X параллельных процессов может быть выполнен с помощью следующего кода :
from multiprocessing import Process
from Queue import Queue
queue = Queue(maxsize=MAX_NODES) # this is the number of processes you will spawn
procs = [Process(target=f, args=(node, queue) for node in nodes] # node will be the node for each process , the queue is common to all of the processes
[p.start() for p in procs] # start them
results = []
for i in range(len(nodes):
results.append(queue.get())
Все, что вам нужно сделать, это изменить функцию (целевую функцию), чтобы принять соответствующее количество аргументов плюс очередь, и в конце вычисления вызвать queue.put(результат)
Надеюсь, это имеет смысл
Комментарии:
1. Я пытался использовать очередь, как вы предлагаете, но она никогда не останавливается! Я знаю, почему. Вы думаете, это потому, что моя функция возвращает ny.darray ? Я не знаю почему. Я также пробовал с пулами, и это тоже не останавливается (я обновляю ваш пост своим кодом). Я не знаю, что делать…