通常の最小自乗回帰を解くための高速座標降下アルゴリズムを作成しようとしています。次ジュリア・コードは動作しますが、それはそんなにメモリに私は私がなぜジュリアはあまりにも多くのメモリを割り当てていますか?
BenchmarkTools.Trial:
memory estimate: 65.94 mb
allocs estimate: 151359
--------------
minimum time: 19.316 ms (16.49% GC)
median time: 20.545 ms (16.60% GC)
mean time: 22.164 ms (16.24% GC)
maximum time: 42.114 ms (10.82% GC)
--------------
samples: 226
evals/sample: 1
time tolerance: 5.00%
memory tolerance: 1.00%
取得@benchmark OLS_cd(X, y)
を使用して
n = 100
p = 75
σ = 0.1
β_nz = float([i*(-1)^i for i in 1:10])
β = append!(β_nz,zeros(p-length(β_nz)))
X = randn(n,p); X .-= mean(X,1); X ./= sqrt(sum(abs2(X),1))
y = X*β + σ*randn(n); y .-= mean(y);
を生成するデータに
function OLS_cd{T<:Float64}(A::Array{T,2}, b::Array{T,1}, tolerance::T=1e-12)
N,P = size(A)
x = zeros(P)
r = copy(b)
d = ones(P)
while sum(d.*d) > tolerance
@inbounds for j = 1:P
d[j] = sum(A[:,j].*r)
x[j] += d[j]
r -= d[j]*A[:,j]
end
end
return(x)
end
を割り当てている理由私は理解していませんp
が大きくなるにつれ、OLSの問題はより難しくなります。私はpを大きくして実行する必要があることに気付きました。
なぜ、それぞれwhile
ループを通過すると、より多くのメモリが割り当てられますか?私の目には、私の操作のすべてが適切であり、タイプが明確に指定されているようです。
プロファイリング中に何も飛び出さなかったが、有用であればその出力も投稿できる。
更新: としてベクトル化操作を使用することによって引き起こされる一時的なアレイが原因であった、以下に指摘。以下は、余分な割り当てを排除し、かなり迅速に実行します:
function OLS_cd_unrolled{T<:Float64}(A::Array{T,2}, b::Array{T,1}, tolerance::T=1e-12)
N,P = size(A)
x = zeros(P)
r = copy(b)
d = ones(P)
while norm(d,Inf) > tolerance
@inbounds for j = 1:P
d[j] = 0.0; @inbounds for i = 1:N d[j] += A[i,j]*r[i] end
@inbounds for i = 1:N r[i] -= d[j]*A[i,j] end
x[j] += d[j]
end
end
return(x)
end
マイナーポイントは、Float64でなければならないと言ったときになぜパラメータ化を使用するのですか?ただそれをT <:Realにするのはもっと強力ではないでしょうか?また、ゼロ(P)と1(P)は正しいタイプを取りません、ゼロ(T、P)と1(T、P)でなければならず、内側のループでd [j] =ゼロ(T)。 –
それは良い点です。私はまだJuliaの型指定のものでかなり荒いです。 – Rory
また、配列からd [j]にアクセスする理由と、なぜ2つのループがあるのですか?どうしてですか? 'dj =ゼロ(T); @inbounds for i = 1:N; aij = A [i、j]; dj + = aij * r [i]である。 r [i] - = dj * aij;終わり ; x [j] + = dj;私は数学者ではないので、ここではすべて濡れているかもしれません。 –