Deferred computation for precompilable tags?
まだ誰も着手していません。
評価
調査の方向性
参照されている ForwardDiff PR #807 のコメントから始め、現在の runtime tagcount パスを調査してください。提案されている Deferred アプローチを Enzyme の autodiff_deferred と比較してください。完了には、ネストされた微分の合意済み設計と、提供された OuterF/InnerF の例をカバーするテストが必要です。
索引モデルが issue の本文から書いたものです。
説明
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
- 主要言語
- Julia
- スター
- 1k
- フォーク
- 162
- PR マージ指標
- 30日以内にマージされた PR はありません
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
JuliaDiff/ForwardDiff.jl のほかの issue
-
missing floatmin, floatmax, and issubnormal for Dual対応中かも @devmotion が 16 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
JuliaDiff/ForwardDiff.jl#852 · コメント 6 件 ·
-
`fma` and `muladd` ignore NaN-safe mode対応中かも @devmotion が 1 日前に担当しました。 オープン
難易度 3/5 1〜2日 初心者へのやさしさ 55/100
JuliaDiff/ForwardDiff.jl#860 ·
-
Enable NaN-safe mode by default対応中かも @devmotion が 3 日前に担当しました。 オープン
難易度 5/5 1週間以上 初心者へのやさしさ 25/100
JuliaDiff/ForwardDiff.jl#857 · リアクション 1 件 ·
-
難易度 4/5 3〜5日 初心者へのやさしさ 52/100
JuliaDiff/ForwardDiff.jl#854 · コメント 1 件 ·
-
難易度 3/5 1〜2日 初心者へのやさしさ 75/100
JuliaDiff/ForwardDiff.jl#849 ·
JuliaDiff/ForwardDiff.jl の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
JuliaGPU/KernelAbstractions.jl#897 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
oscar-system/GAP.jl#1455 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
JuliaAI/MLJTransforms.jl#85 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
SciML/OrdinaryDiffEq.jl#4875 ·
メンテナーはふだん 4 日以内に返信