Случайное блуждание — параллельная обработка

#python #parallel-processing #montecarlo

#python #параллельная обработка #Монтекарло

Вопрос:

В настоящее время я реализую метод Монте-Карло для решения уравнения диффузии. Решение может быть выражено как математическое ожидание phi (W), где phi — функция (изменяется в соответствии с уравнением диффузии), а W — симметричное случайное блуждание, остановленное на границе области. Чтобы оценить функцию в точке x, мне нужно начинать каждое блуждание в ожидании от x.

Я хочу оценить функцию по большому количеству точек. Итак, это то, что я делаю:

  1. Я начинаю одновременно одно прохождение с каждой точки
  2. Я использую одни и те же шаги для каждой точки
  3. Как только каждое блуждание достигает границы, я останавливаюсь
  4. Я повторяю эти операции 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 ? Я не знаю почему. Я также пробовал с пулами, и это тоже не останавливается (я обновляю ваш пост своим кодом). Я не знаю, что делать…