Skip to content

Commit 624039b

Browse files
committed
Minor perf improvements for gradients.
1 parent 2a510c8 commit 624039b

File tree

1 file changed

+75
-18
lines changed

1 file changed

+75
-18
lines changed

src/gradients.jl

Lines changed: 75 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,18 @@ function GradientCache(
2323
end
2424

2525
if typeof(x)<:AbstractArray # the vector->scalar case
26-
# need cache arrays for epsilon (c1) and x1 (c2)
26+
# need cache arrays for x1 (c1) and epsilon (c2, only if non-StridedArray)
2727
if fdtype!=Val{:complex} # complex-mode FD only needs one cache, for x+eps*im
28-
if typeof(c1)==Void || eltype(c1)!=real(eltype(x))
29-
_c1 = zeros(real(eltype(x)), size(x))
28+
if typeof(c1)!=typeof(x) || size(c1)!=size(x)
29+
_c1 = similar(x)
3030
else
3131
_c1 = c1
3232
end
33-
if typeof(c2)!=typeof(x) || size(c2)!=size(x)
34-
_c2 = similar(x)
33+
if typeof(c2)!=Void && x<:StridedVector
34+
warn("c2 cache isn't necessary when x<:StridedVector.")
35+
end
36+
if typeof(c2)==Void || eltype(c2)!=real(eltype(x)) && !(x<:StridedVector)
37+
_c2 = zeros(real(eltype(x)), size(x))
3538
else
3639
_c2 = c2
3740
end
@@ -128,46 +131,100 @@ function finite_difference_gradient!(df::AbstractArray{<:Number}, f, x::Abstract
128131
cache::GradientCache{T1,T2,T3,fdtype,returntype,inplace}) where {T1,T2,T3,fdtype,returntype,inplace}
129132

130133
# NOTE: in this case epsilon is a vector, we need two arrays for epsilon and x1
131-
# c1 denotes epsilon, c2 is x1, pre-set to the values of x by the cache constructor
134+
# c1 denotes x1, c2 is epsilon
132135
fx, c1, c2 = cache.fx, cache.c1, cache.c2
133136
if fdtype != Val{:complex}
134137
epsilon_factor = compute_epsilon_factor(fdtype, eltype(x))
135-
@. c1 = compute_epsilon(fdtype, x, epsilon_factor)
136-
copy!(c2,x)
138+
@. c2 = compute_epsilon(fdtype, x, epsilon_factor)
139+
copy!(c1,x)
137140
end
138141
if fdtype == Val{:forward}
139142
@inbounds for i eachindex(x)
140-
c2[i] += c1[i]
143+
epsilon = c2[i]
144+
c1_old = c1[i]
145+
c1[i] += epsilon
141146
if typeof(fx) != Void
142-
df[i] = (f(c2) - fx) / c1[i]
147+
df[i] = (f(c1) - fx) / epsilon
143148
else
144-
df[i] = (f(c2) - f(x)) / c1[i]
149+
df[i] = (f(c1) - f(x)) / epsilon
145150
end
146-
c2[i] -= c1[i]
151+
c1[i] = c1_old
147152
end
148153
elseif fdtype == Val{:central}
149154
@inbounds for i eachindex(x)
150-
c2[i] += c1[i]
151-
x[i] -= c1[i]
152-
df[i] = (f(c2) - f(x)) / (2*c1[i])
153-
c2[i] -= c1[i]
154-
x[i] += c1[i]
155+
epsilon = c2[i]
156+
c1_old = c1[i]
157+
c1[i] += epsilon
158+
x_old = x[i]
159+
x[i] -= epsilon
160+
df[i] = (f(c1) - f(x)) / (2*epsilon)
161+
c1[i] = c1_old
162+
x[i] = x_old
155163
end
156164
elseif fdtype == Val{:complex} && returntype <: Real
157165
copy!(c1,x)
158166
epsilon_complex = eps(real(eltype(x)))
159167
# we use c1 here to avoid typing issues with x
160168
@inbounds for i eachindex(x)
169+
c1_old = c1[i]
161170
c1[i] += im*epsilon_complex
162171
df[i] = imag(f(c1)) / epsilon_complex
163-
c1[i] -= im*epsilon_complex
172+
c1[i] = c1_old
164173
end
165174
else
166175
fdtype_error(returntype)
167176
end
168177
df
169178
end
179+
#=
180+
function finite_difference_gradient!(df::StridedVector{<:Number}, f, x::StridedVector{<:Number},
181+
cache::GradientCache{T1,T2,T3,fdtype,returntype,inplace}) where {T1,T2,T3,fdtype,returntype,inplace}
170182
183+
# c1 is x1, c2 shouldn't exist in this case
184+
fx, c1, c2 = cache.fx, cache.c1, cache.c2
185+
if fdtype != Val{:complex}
186+
epsilon_factor = compute_epsilon_factor(fdtype, eltype(x))
187+
copy!(c1,x)
188+
end
189+
if fdtype == Val{:forward}
190+
@inbounds for i ∈ eachindex(x)
191+
epsilon = compute_epsilon(fdtype, x[i], epsilon_factor)
192+
c2_old = c2[i]
193+
c2[i] += epsilon
194+
if typeof(fx) != Void
195+
df[i] = (f(c2) - fx) / epsilon
196+
else
197+
df[i] = (f(c2) - f(x)) / epsilon
198+
end
199+
c2[i] = c2_old
200+
end
201+
elseif fdtype == Val{:central}
202+
@inbounds for i ∈ eachindex(x)
203+
epsilon = compute_epsilon(fdtype, x[i], epsilon_factor)
204+
c2_old = c2[i]
205+
c2[i] += epsilon
206+
x_old = x[i]
207+
x[i] -= epsilon
208+
df[i] = (f(c2) - f(x)) / (2*epsilon)
209+
c2[i] = c2_old
210+
x[i] = x_old
211+
end
212+
elseif fdtype == Val{:complex} && returntype <: Real
213+
copy!(c1,x)
214+
epsilon_complex = eps(real(eltype(x)))
215+
# we use c1 here to avoid typing issues with x
216+
@inbounds for i ∈ eachindex(x)
217+
c1_old = c1[i]
218+
c1[i] += im*epsilon_complex
219+
df[i] = imag(f(c1)) / epsilon_complex
220+
c1[i] = c1_old
221+
end
222+
else
223+
fdtype_error(returntype)
224+
end
225+
df
226+
end
227+
=#
171228
# vector of derivatives of a scalar->vector map
172229
# this is effectively a vector of partial derivatives, but we still call it a gradient
173230
function finite_difference_gradient!(df::AbstractArray{<:Number}, f, x::Number,

0 commit comments

Comments
 (0)