gpt4 book ai didi

parallel-processing - Julia 中的并行化梯度计算

转载 作者:行者123 更新时间:2023-12-04 11:36:18 25 4
gpt4 key购买 nike

前段时间我被说服放弃我舒适的 matlab 编程并开始在 Julia 中编程。我一直在研究神经网络,我认为现在有了 Julia,我可以通过并行化梯度计算来更快地完成工作。

不需要一次性计算整个数据集的梯度;相反,可以拆分计算。例如,通过将数据集分成几部分,我们可以计算每个部分的部分梯度。然后通过将部分梯度相加来计算总梯度。

不过,原理很简单,当我与 Julia 并行时,性能会下降,即一个进程比两个进程快!我显然做错了什么......我已经咨询了论坛中提出的其他问题,但我仍然无法拼凑出答案。我认为我的问题在于有很多不必要的数据在移动,但我无法正确修复它。

为了避免发布凌乱的神经网络代码,我在下面发布了一个更简单的示例,该示例在线性回归的设置中复制了我的问题。

下面的代码块为线性回归问题创建了一些数据。代码解释了常量,但 X 是包含数据输入的矩阵。我们随机创建一个权重向量 w 当与 相乘时X 创建一些目标 .

######################################
## CREATE LINEAR REGRESSION PROBLEM ##
######################################

# This code implements a simple linear regression problem

MAXITER = 100 # number of iterations for simple gradient descent
N = 10000 # number of data items
D = 50 # dimension of data items
X = randn(N, D) # create random matrix of data, data items appear row-wise
Wtrue = randn(D,1) # create arbitrary weight matrix to generate targets
Y = X*Wtrue # generate targets

下面的下一个代码块定义了用于测量回归适应度(即负对数似然)和权重向量梯度 的函数。 w:
####################################
## DEFINE FUNCTIONS ##
####################################

@everywhere begin

#-------------------------------------------------------------------
function negative_loglikelihood(Y,X,W)
#-------------------------------------------------------------------

# number of data items
N = size(X,1)
# accumulate here log-likelihood
ll = 0
for nn=1:N
ll = ll - 0.5*sum((Y[nn,:] - X[nn,:]*W).^2)
end

return ll
end


#-------------------------------------------------------------------
function negative_loglikelihood_grad(Y,X,W, first_index,last_index)
#-------------------------------------------------------------------

# number of data items
N = size(X,1)
# accumulate here gradient contributions by each data item
grad = zeros(similar(W))
for nn=first_index:last_index
grad = grad + X[nn,:]' * (Y[nn,:] - X[nn,:]*W)
end

return grad
end


end

请注意,上述函数是故意没有向量化的!我选择不进行矢量化,因为最终代码(神经网络案例)也不会接受任何矢量化(让我们不要深入了解更多细节)。

最后,下面的代码块显示了一个非常简单的梯度下降,它试图恢复参数权重向量 w 从给定的数据 X :
####################################
## SOLVE LINEAR REGRESSION ##
####################################


# start from random initial solution
W = randn(D,1)

# learning rate, set here to some arbitrary small constant
eta = 0.000001

# the following for-loop implements simple gradient descent
for iter=1:MAXITER

# get gradient
ref_array = Array(RemoteRef, nworkers())

# let each worker process part of matrix X
for index=1:length(workers())

# first index of subset of X that worker should work on
first_index = (index-1)*int(ceil(N/nworkers())) + 1
# last index of subset of X that worker should work on
last_index = min((index)*(int(ceil(N/nworkers()))), N)

ref_array[index] = @spawn negative_loglikelihood_grad(Y,X,W, first_index,last_index)
end

# gather the gradients calculated on parts of matrix X
grad = zeros(similar(W))
for index=1:length(workers())
grad = grad + fetch(ref_array[index])
end

# now that we have the gradient we can update parameters W
W = W + eta*grad;

# report progress, monitor optimisation
@printf("Iter %d neg_loglikel=%.4f\n",iter, negative_loglikelihood(Y,X,W))
end

正如希望看到的那样,我在这里尝试以最简单的方式并行计算梯度。我的策略是在尽可能多的可用 worker 中打破梯度计算。每个 worker 只需要处理矩阵 X 的一部分,这部分由 first_index 和 last_index 指定。因此,每个 worker 都应该与 X[first_index:last_index,:] 一起工作。 .例如,对于 4 个 worker 和 N = 10000,工作应划分如下:
  • worker 1 => first_index = 1,last_index = 2500
  • worker 2 => first_index = 2501,last_index = 5000
  • worker 3 => first_index = 5001,last_index = 7500
  • worker 4 => first_index = 7501,last_index = 10000

  • 不幸的是,如果我只有一个 worker ,那么整个代码的运行速度会更快。如果通过 addprocs() 添加更多 worker ,代码运行速度较慢。可以通过创建更多数据项来加剧这一问题,例如使用 N=20000。
    随着数据项的增多,降级更加明显。
    在我的 N=20000 和一个内核的特定计算环境中,代码运行时间约为 9 秒。使用 N=20000 和 4 个内核,大约需要 18 秒!

    受此论坛中的问题和答案的启发,我尝试了许多不同的事情,但不幸的是无济于事。我意识到并行化是幼稚的,数据移动一定是问题所在,但我不知道如何正确地做到这一点。似乎关于这个问题的文档也有点稀缺(Ivo Balbaert 的好书也是如此)。

    我很感激你的帮助,因为我已经被这个问题困住了很长一段时间,我的工作真的需要它。对于任何想要运行代码的人,为了省去复制粘贴的麻烦,您可以获取代码 here .

    感谢您花时间阅读这个冗长的问题!帮我把它变成一个模型答案,任何 Julia 的新手都可以咨询!

    最佳答案

    如果您想减少数据移动量,您应该强烈考虑使用 SharedArrays。您可以只预先分配一个输出向量,并将其作为参数传递给每个工作人员。正如您所建议的那样,每个工作人员都会设置其中的一部分。

    关于parallel-processing - Julia 中的并行化梯度计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31656858/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com