Deferred computation for precompilable tags?
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 5/5
- Thời gian dự kiến
- Hơn một tuần
- Mức phù hợp với người mới
- 35/100
Hướng nghiên cứu
Bắt đầu với bình luận được tham chiếu của ForwardDiff PR #807 và kiểm tra đường dẫn runtime tagcount hiện tại. So sánh cách tiếp cận Deferred được đề xuất với autodiff_deferred của Enzyme; để hoàn thành sẽ cần một thiết kế được thống nhất cho phép vi phân lồng nhau và các bài kiểm thử bao quát ví dụ OuterF/InnerF đã cung cấp.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
I was looking at https://github.com/JuliaDiff/ForwardDiff.jl/pull/807 and this comment caught my attention:
The pattern (outer derivative of an inner scalar derivative whose closure captures the outer point) is the canonical scalar nested derivative — it isn't exotic, and it's exactly what would be expected to suffer from precompile-induced tagcount inversion in downstream packages.
When the inner derivative is seeded with a literal Float64, the inner tag is Tag{, Float64} with depth 1 — even though that closure captures a Dual{T_middle, ..., 2} (the outer-nesting context is in F, not in V)
As of ForwardDiff.jl v1.4 the closure-over-AD pattern is solved via the runtime tagcount mechanism.
another known AD framework with forward mode is Enzyme, and they explicitly provide a separate function to allow nested differentiation, namely (autodiff_deferred).
is it possible to implement a similar mechanism in ForwardDiff?. Instead of recursing over the closure type, at closure construction a Deferred{F,T} struct is created that stores, along with the closure, tag information that could be exposed to the outer ForwardDiff contexts?. For example here:
using ForwardDiff
const Tag = ForwardDiff.Tag
struct OuterF end
struct InnerF
x_dual::ForwardDiff.Dual{Tag{OuterF, Float64}, Float64, 1}
end
(c::InnerF)(y) = sin(c.x_dual * y)
(::OuterF)(x_dual::ForwardDiff.Dual{Tag{OuterF, Float64}, Float64, 1}) =
ForwardDiff.derivative(InnerF(x_dual), 1.0)
# Force tagcount to be evaluated in INVERTED order (simulating a precompile race):
ForwardDiff.tagcount(Tag{InnerF, Float64}) # returns 0
ForwardDiff.tagcount(Tag{OuterF, Float64}) # returns 1
# Analytic: d/dx (d/dy sin(x*y)|_{y=1}) at x=0.5 = cos(0.5) - 0.5*sin(0.5) ≈ 0.6378697925882713
ForwardDiff.derivative(OuterF(), 0.5)
The current path creates the two tags Tag{InnerF, Float64} and Tag{OuterF, Float64}. But if we had something like:
struct Deferred{F,P}
F::F #function to be evaluated
p::P #context
end
(f::Deferred{FF,PP})(x) where {FF,PP} = f.F(f.p)(x)
#TODO: generalize for abstract arrays and other contexts.
deferred_valtype(::Type{V},p::T) where {V<:Number,T<:Number} = promote_type(V,T)
function ForwardDiff.Tag(f::Deferred{F,P},::Type{V}) where {F,P,V}
return ForwardDiff.Tag(f.F,deferred_valtype(V,f.p))
end
#use deferred instead of instantiating InnerF directly
(::OuterF)(x_dual::ForwardDiff.Dual{Tag{OuterF, Float64}, Float64, 1}) =
ForwardDiff.derivative(Deferred(InnerF,x_dual), 1.0)
#a macro for user convenience:
#(::OuterF)(x_dual::ForwardDiff.Dual{Tag{OuterF, Float64}, Float64, 1}) =
ForwardDiff.derivative(@deferred(InnerF(x_dual)), 1.0)
ForwardDiff.derivative(OuterF(), 0.5) #0.6378697925882713
In this case, the tags created would be Tag{OuterF,Float64} and Tag{InnerF,Dual{OuterF, Float64}, Float64, 1}, but that is because we transformed the problem into one that is more amenable to what ForwardDiff already does, while giving a path for tag comparisons that don't depend on a global variable that could change between sessions
- Ngôn ngữ chính
- Julia
- Star
- 1k
- Fork
- 162
- Chỉ số merge pull request
- Không có pull request nào được merge trong 30 ngày
Chuẩn bị môi trường
Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của JuliaDiff/ForwardDiff.jl
-
missing floatmin, floatmax, and issubnormal for DualCó thể đã có người làm @devmotion đã nhận 14 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
JuliaDiff/ForwardDiff.jl#852 · 6 bình luận ·
-
Enable NaN-safe mode by defaultCó thể đã có người làm @devmotion đã nhận 1 ngày trước. Đang mở
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 25/100
JuliaDiff/ForwardDiff.jl#857 · 1 reaction ·
-
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 52/100
JuliaDiff/ForwardDiff.jl#854 · 1 bình luận ·
-
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 75/100
JuliaDiff/ForwardDiff.jl#849 ·
-
`gradient!` leaves part of the result unwritten when `f` does not depend on its argumentCó thể đã có người làm @devmotion đã nhận 43 ngày trước. Đang mở
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 78/100
JuliaDiff/ForwardDiff.jl#847 ·
Tất cả issue của JuliaDiff/ForwardDiff.jl
Issue tương tự
-
documentation
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 Dưới một giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
CliMA/ClimaAtmos.jl#4891 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
tagbot-manual
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 75/100
tshort/StaticCompiler.jl#191 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
SciML/SciMLSensitivity.jl#1703 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày