Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 81 additions & 78 deletions .github/workflows/Test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,29 +28,30 @@ jobs:
fail-fast: true # TODO: toggle
matrix:
version:
- '1.10'
# - '1.10'
- '1.11'
- '1.12'
group:
- Core/Internals
- Back/DifferentiateWith
- Core/SimpleFiniteDiff
- Back/SparsityDetector
- Core/ZeroBackends
- Back/ChainRules
# - Back/Diffractor
- Back/Enzyme
- Back/FastDifferentiation
- Back/FiniteDiff
- Back/FiniteDifferences
- Back/ForwardDiff
- Back/GTPSA
- Back/Mooncake
- Back/PolyesterForwardDiff
- Back/ReverseDiff
- Back/Symbolics
- Back/Tracker
- Back/Zygote
# - Core/Internals
# - Back/DifferentiateWith
# - Core/SimpleFiniteDiff
# - Back/SparsityDetector
# - Core/ZeroBackends
# - Back/ChainRules
# # - Back/Diffractor
# - Back/Enzyme
# - Back/FastDifferentiation
# - Back/FiniteDiff
# - Back/FiniteDifferences
# - Back/ForwardDiff
# - Back/GTPSA
# - Back/Mooncake
# - Back/PolyesterForwardDiff
- Back/Reactant
# - Back/ReverseDiff
# - Back/Symbolics
# - Back/Tracker
# - Back/Zygote
skip_lts:
- ${{ github.event.pull_request.draft }}
skip_pre:
Expand All @@ -64,6 +65,8 @@ jobs:
group: Back/ChainRules
- version: '1.12'
group: Back/Enzyme
- version: '1.12'
group: Back/Reactant
- version: '1.12'
group: Back/DifferentiateWith
env:
Expand Down Expand Up @@ -104,61 +107,61 @@ jobs:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false

test-DIT:
name: ${{ matrix.version }} - DIT (${{ matrix.group }})
runs-on: ubuntu-latest
if: ${{ !contains(github.event.pull_request.labels.*.name, 'skipci') }}
timeout-minutes: 60
permissions: # needed to allow julia-actions/cache to proactively delete old caches that it has created
actions: write
contents: read
strategy:
fail-fast: true
matrix:
version:
- '1.10'
- '1.11'
- '1.12'
group:
- Formalities
- Zero
- Standard
- Weird
skip_lts:
- ${{ github.event.pull_request.draft }}
skip_pre:
- ${{ github.event.pull_request.draft }}
exclude:
- skip_lts: true
version: '1.10'
- skip_pre: true
version: '1.12'
env:
JULIA_DIT_TEST_GROUP: ${{ matrix.group }}
JULIA_DI_PR_DRAFT: ${{ github.event.pull_request.draft }}
steps:
- uses: actions/checkout@v5
- uses: julia-actions/setup-julia@v2
with:
version: ${{ matrix.version }}
arch: x64
- uses: julia-actions/cache@v2
- name: Install dependencies & run tests
run: julia --project=./DifferentiationInterfaceTest --color=yes -e '
using Pkg;
Pkg.Registry.update();
Pkg.develop(path="./DifferentiationInterface");
if ENV["JULIA_DI_PR_DRAFT"] == "true";
Pkg.test("DifferentiationInterfaceTest"; allow_reresolve=false, coverage=true, julia_args=["-O1"]);
else;
Pkg.test("DifferentiationInterfaceTest"; allow_reresolve=false, coverage=true);
end;'
- uses: julia-actions/julia-processcoverage@v1
with:
directories: ./DifferentiationInterfaceTest/src,./DifferentiationInterfaceTest/ext,./DifferentiationInterfaceTest/test
- uses: codecov/codecov-action@v5
with:
files: lcov.info
flags: DIT
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
# test-DIT:
# name: ${{ matrix.version }} - DIT (${{ matrix.group }})
# runs-on: ubuntu-latest
# if: ${{ !contains(github.event.pull_request.labels.*.name, 'skipci') }}
# timeout-minutes: 60
# permissions: # needed to allow julia-actions/cache to proactively delete old caches that it has created
# actions: write
# contents: read
# strategy:
# fail-fast: true
# matrix:
# version:
# - '1.10'
# - '1.11'
# - '1.12'
# group:
# - Formalities
# - Zero
# - Standard
# - Weird
# skip_lts:
# - ${{ github.event.pull_request.draft }}
# skip_pre:
# - ${{ github.event.pull_request.draft }}
# exclude:
# - skip_lts: true
# version: '1.10'
# - skip_pre: true
# version: '1.12'
# env:
# JULIA_DIT_TEST_GROUP: ${{ matrix.group }}
# JULIA_DI_PR_DRAFT: ${{ github.event.pull_request.draft }}
# steps:
# - uses: actions/checkout@v5
# - uses: julia-actions/setup-julia@v2
# with:
# version: ${{ matrix.version }}
# arch: x64
# - uses: julia-actions/cache@v2
# - name: Install dependencies & run tests
# run: julia --project=./DifferentiationInterfaceTest --color=yes -e '
# using Pkg;
# Pkg.Registry.update();
# Pkg.develop(path="./DifferentiationInterface");
# if ENV["JULIA_DI_PR_DRAFT"] == "true";
# Pkg.test("DifferentiationInterfaceTest"; allow_reresolve=false, coverage=true, julia_args=["-O1"]);
# else;
# Pkg.test("DifferentiationInterfaceTest"; allow_reresolve=false, coverage=true);
# end;'
# - uses: julia-actions/julia-processcoverage@v1
# with:
# directories: ./DifferentiationInterfaceTest/src,./DifferentiationInterfaceTest/ext,./DifferentiationInterfaceTest/test
# - uses: codecov/codecov-action@v5
# with:
# files: lcov.info
# flags: DIT
# token: ${{ secrets.CODECOV_TOKEN }}
# fail_ci_if_error: false
5 changes: 4 additions & 1 deletion DifferentiationInterface/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ GPUArraysCore = "46192b85-c4d5-4398-a991-12ede77f4527"
GTPSA = "b27dd330-f138-47c5-815b-40db9dd9b6e8"
Mooncake = "da2b9cff-9c12-43a0-ae48-6db2b0edb7d6"
PolyesterForwardDiff = "98d1487c-24ca-40b6-b7ab-df2af84e126b"
Reactant = "3c362404-f566-11ee-1572-e11a4b42c853"
ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
SparseConnectivityTracer = "9f842d2f-2579-4b1d-911e-f412cf18a3f5"
Expand All @@ -46,6 +47,7 @@ DifferentiationInterfacePolyesterForwardDiffExt = [
"ForwardDiff",
"DiffResults",
]
DifferentiationInterfaceReactantExt = ["Reactant", "Enzyme"]
DifferentiationInterfaceReverseDiffExt = ["ReverseDiff", "DiffResults"]
DifferentiationInterfaceSparseArraysExt = "SparseArrays"
DifferentiationInterfaceSparseConnectivityTracerExt = "SparseConnectivityTracer"
Expand All @@ -56,7 +58,7 @@ DifferentiationInterfaceTrackerExt = "Tracker"
DifferentiationInterfaceZygoteExt = ["Zygote", "ForwardDiff"]

[compat]
ADTypes = "1.18.0"
ADTypes = "1.19.0"
ChainRulesCore = "1.23.0"
DiffResults = "1.1.0"
Diffractor = "=0.2.6"
Expand All @@ -71,6 +73,7 @@ GTPSA = "1.4.0"
LinearAlgebra = "1"
Mooncake = "0.4.175"
PolyesterForwardDiff = "0.1.2"
Reactant = "0.2.178"
ReverseDiff = "1.15.1"
SparseArrays = "1"
SparseConnectivityTracer = "0.6.14, 1"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module DifferentiationInterfaceReactantExt

using ADTypes: ADTypes, AutoReactant
import DifferentiationInterface as DI
using Reactant: @compile, to_rarray

DI.check_available(backend::AutoReactant) = DI.check_available(backend.mode)
DI.inplace_support(backend::AutoReactant) = DI.inplace_support(backend.mode)

include("onearg.jl")

end # module
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
struct ReactantGradientPrep{SIG, XR, GR, CG, CG!, CVG, CVG!} <: DI.GradientPrep{SIG}
_sig::Val{SIG}
xr::XR
gr::GR
compiled_gradient::CG
compiled_gradient!::CG!
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we have different prep objects for each of the compiled variants. Reason being that one may compile whereas the other may not.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what you mean here. You want to explore all 2^4 combinations of compiled/non-compiled operator variants?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean that we should have distinct

struct ReactantGradientPrep
    compiled_gradient::CG
end

struct ReactantGradient!Prep
    compiled_gradient!::CG!
end

struct ReactantValueAndGradient!Prep
    compiled_value_and_gradient!::CG!
end

....

perhaps they can be templated or anything else, but they should be distinct (and therefore prepare should only compile for the one that will be used)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is not compatible with DI's API. A preparation result must allow calling all four variants of an operator.
Would it speed things up if the compiled versions built off one another?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, and rip that seems like a design limitation of DI.

Is it something that's fixable in time?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just because you don't like it doesn't automatically mean it is a design limitation, it could also just be a design decision you disagree with 😉 In fact, it is completely consistent with the way most backends work, otherwise I would have done it differently. And it is rather convenient for users having 1 preparation for 4 variants.

It is not fixable without a breaking release, which I'm fairly reluctant to do given that we have 1000 indirect dependents.
Even if we did introduce variants like prepare_gradient! or prepare_value_and_gradient, which we can do fairly easily, the basic prepare_gradient would still need to prepare for all 4 variants.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #685 to continue this design discussion (I opened this issue a year ago ^^)

compiled_value_and_gradient::CVG
compiled_value_and_gradient!::CVG!
end

function DI.prepare_gradient_nokwarg(strict::Val, f::F, rebackend::AutoReactant, x) where {F}
_sig = DI.signature(f, rebackend, x; strict)
backend = rebackend.mode
xr = to_rarray(x)
gr = to_rarray(similar(x))
_gradient(_xr) = DI.gradient(f, backend, _xr)
_gradient!(_gr, _xr) = copy!(_gr, DI.gradient(f, backend, _xr))
_value_and_gradient(_xr) = DI.value_and_gradient(f, backend, _xr)
function _value_and_gradient!(_gr, _xr)
y, __gr = DI.value_and_gradient(f, backend, _xr)
copy!(_gr, __gr)
return y, _gr
end
compiled_gradient = @compile _gradient(xr)
compiled_gradient! = @compile _gradient!(gr, xr)
compiled_value_and_gradient = @compile _value_and_gradient(xr)
compiled_value_and_gradient! = @compile _value_and_gradient!(gr, xr)
return ReactantGradientPrep(
_sig,
xr,
gr,
compiled_gradient,
compiled_gradient!,
compiled_value_and_gradient,
compiled_value_and_gradient!,
)
end

function DI.gradient(
f::F, prep::ReactantGradientPrep, rebackend::AutoReactant, x
) where {F}
DI.check_prep(f, prep, rebackend, x)
(; xr, compiled_gradient) = prep
copy!(xr, x)
gr = compiled_gradient(xr)
g = convert(typeof(x), gr)
return g
end

function DI.value_and_gradient(
f::F, prep::ReactantGradientPrep, rebackend::AutoReactant, x
) where {F}
DI.check_prep(f, prep, rebackend, x)
(; xr, compiled_value_and_gradient) = prep
copy!(xr, x)
yr, gr = compiled_value_and_gradient(xr)
y = convert(eltype(x), yr)
g = convert(typeof(x), gr)
return y, g
end

function DI.gradient!(
f::F, grad, prep::ReactantGradientPrep, rebackend::AutoReactant, x
) where {F}
DI.check_prep(f, prep, rebackend, x)
(; xr, gr, compiled_gradient!) = prep
copy!(xr, x)
compiled_gradient!(gr, xr)
return copy!(grad, gr)
end

function DI.value_and_gradient!(
f::F, grad, prep::ReactantGradientPrep, rebackend::AutoReactant, x
) where {F}
DI.check_prep(f, prep, rebackend, x)
(; xr, gr, compiled_value_and_gradient!) = prep
copy!(xr, x)
yr, gr = compiled_value_and_gradient!(gr, xr)
y = convert(eltype(x), yr)
return y, copy!(grad, gr)
end
2 changes: 2 additions & 0 deletions DifferentiationInterface/src/DifferentiationInterface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ using ADTypes:
AutoMooncake,
AutoMooncakeForward,
AutoPolyesterForwardDiff,
AutoReactant,
AutoReverseDiff,
AutoSymbolics,
AutoTracker,
Expand Down Expand Up @@ -118,6 +119,7 @@ export AutoGTPSA
export AutoMooncake
export AutoMooncakeForward
export AutoPolyesterForwardDiff
export AutoReactant
export AutoReverseDiff
export AutoSymbolics
export AutoTracker
Expand Down
14 changes: 14 additions & 0 deletions DifferentiationInterface/test/Back/Reactant/test.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Pkg
Pkg.add("Reactant")

using DifferentiationInterface
using DifferentiationInterfaceTest
using Reactant

backend = AutoReactant()

test_differentiation(
backend, DifferentiationInterfaceTest.default_scenarios();
excluded = vcat(SECOND_ORDER, :jacobian, :derivative, :pushforward, :pullback),
logging = true
)
Loading