Julia @spawn и pmap () о смущающе параллельной задаче, требующей JuMP и Ipopt - PullRequest
0 голосов
/ 06 июля 2019

Я бы очень признателен за помощь в распараллеливании следующего псевдокода в Julia (и я заранее извиняюсь за длинный пост):

P, Q   # both K by N matrix, K = num features and N = num samples
X, Y   # K*4 by N and K*2 by N matrices
tempX, tempY  # column vectors of size K*4 and K*2
ndata  # a dict from parsing a .m file to be used by a solver with JuMP and Ipopt

# serial version
for i = 1:N
    ndata[P] = P[:, i]  # technically requires a for loop from 1 to K since the dict has to be indexed element-wise
    ndata[Q] = Q[:, i]

    ndata_A = run_solver_A(ndata)  # with a third-party package and JuMP, Ipopt
    ndata_B = run_solver_B(ndata)

    kX = 1, kY = 1
    for j = 1:K
        tempX[kX:kX+3] = [ndata_A[j][a], ndata_A[j][b], P[j, i], Q[j, i]]
        tempY[kY:kY+1] = [ndata_B[j][a], ndata_B[j][b]]
        kX += 4
        kY += 2
    end
    X[:, i] = deepcopy(tempX)
    Y[:, i] = deepcopy(tempY)
end

Очевидно, что этот цикл for может выполняться независимо, если нет доступа к столбцам P и Q дважды и один и тот же столбец i из P и Q доступен при время. Единственное, с чем мне нужно быть осторожным, это то, что столбцы i из X и Y являются правильными парами tempX и tempY, и меня не волнует, действительно ли i = 1, ..., N порядок поддерживается (надеюсь, это имеет смысл!).

Я прочитал официальную документацию и некоторые онлайн-уроки и написал следующее с @spawn и fetch, который работает для вставной части, заменив ndata[j][a] и т. Д. На номера заполнителей 1.0 и 180:

using Distributed

addprocs(2)
num_proc = nprocs()

@everywhere function insertPQ(P, Q)
    println(myid())
    data = zeros(4*length(P))
    k = 1
    for i = 1:length(P)
        data[k:k+3] = [1.0, 180., P[i], Q[i]]
        k += 4
    end
    return data
end

P = [0.99, 0.99, 0.99, 0.99]
Q = [-0.01, -0.01, -0.01, -0.01]
for i = 1:5  # should be 4 x 32
    global P = hcat(P, (P .- 0.01))
    global Q = hcat(Q, (Q .- 0.01))
end

datas = zeros(16, 0)  # serial result
datap = zeros(16, 32)  # parallel result

@time for i = 1:32
    s =  fetch(@spawn insertPQ(P[:, i], Q[:, i]))
    global datap = hcat(datap, s)
end

@time for i = 1:32
    k = 1
    for j = 1:4
        datas[k:k+3, i] = [1.0, 180., P[j, i], Q[j, i]]
        k += 4
    end
end

println(datap == datas)

Приведенный выше код в порядке, но я заметил, что вывод был последовательно рабочий 2-> 3-> 4-> 5-> 2 ... и был намного медленнее, чем последовательный случай (я тестирую это на своем ноутбуке только с 4 ядрами, но в конечном итоге я буду запускать его на кластере). Потребовалось целую вечность для запуска при добавлении в run_solver_A/B в insertPQ(), что мне пришлось остановить его.

Что касается pmap(), я не мог понять, как передать весь вектор в функцию. Я, вероятно, неправильно понял документацию, но «Преобразование коллекции c путем применения f к каждому элементу с использованием доступных рабочих и задач» звучит так, как будто я могу сделать это только поэлементно? Этого не может быть. На прошлой неделе я пошел на вступительное занятие Джулии и спросил об этом лектора. Он сказал, что я должен использовать pmap, и с тех пор я пытаюсь заставить его работать.

Итак, как я могу распараллелить мой исходный псевдокод? Любая помощь или предложение с благодарностью!

...