Skip to content

Multiple active arguments? #508

Closed
Closed

Description

@gdalle

With v0.6, DI supports any number of context arguments (constants or caches), but only a single active argument x (which comes first).
The last step to full generality is support for any number of active arguments. This would improve performance e.g. with Enzyme, and also (apparently) avoid some differentiation errors.

The issue is that for multiple active arguments, every operator output must become a tuple instead of a single object. In addition to being another breaking change, that might slow down backends which do not support multiple arguments.

My workaround idea for now is:

  1. force the first argument to always be active
  2. if there are no other active arguments (easy to check by constraining the Vararg), return single objects
  3. otherwise, return tuples

Related past discussions:

Activity

  1. changed the title [-]Automatically gather several active arguments?[/-] [+]Multiple active arguments?[/+] on Sep 28, 2024
  2. wsmoses commented on Sep 28, 2024

    @wsmoses

    recopying from slackhole:

    using Enzyme, BenchmarkTools, ADTypes, DifferentiationInterface
    
    mul(a, b) = @inbounds (a[1] * b[1])
    
    const a = [2.0]
    const b = [3.0]
    Enzyme.gradient(Reverse, mul, a, b)
    
    @btime Enzyme.gradient($Reverse, $mul, $a, $b) # 52.496 ns (2 allocations: 128 bytes)
    
    fuse(tup) = mul(tup[1], tup[2])
    
    function bench_di(backend, a, b)
       prep = DifferentiationInterface.prepare_gradient(fuse, backend, (a, b))
       @btime DifferentiationInterface.gradient($fuse, $prep, $backend, $((a, b)))
       return nothing
    end
    
    bench_di(AutoEnzyme(), a, b) #  131.136 ns (4 allocations: 464 bytes)
    
    @btime Enzyme.gradient(Reverse, fuse, $((a, b)) #  129.619 ns (4 allocations: 464 bytes)
  3. wsmoses commented on Sep 28, 2024

    @wsmoses

    and

    using Enzyme, BenchmarkTools, ADTypes, DifferentiationInterface, StaticArrays
    
    mul(a, b) = @inbounds a[1] * sum(b)
    
    const a = [2.0]
    const b = @SMatrix ones(8,8)
    Enzyme.gradient(Reverse, mul, a, b)
    
    @btime Enzyme.gradient($Reverse, $mul, $a, $b) #  7.183 μs (13 allocations: 3.45 KiB)
    
    fuse(tup) = mul(tup[1], tup[2])
    
    function bench_di(backend, a, b)
       prep = DifferentiationInterface.prepare_gradient(fuse, backend, (a, b))
       @btime DifferentiationInterface.gradient($fuse, $prep, $backend, $((a, b)))
       return nothing
    end
    
    bench_di(AutoEnzyme(), a, b) #   27.910 μs (164 allocations: 11.50 KiB)
    
    @btime Enzyme.gradient(Reverse, fuse, $((a, b))) #  27.810 μs (163 allocations: 10.97 KiB)
  4. added
    coreRelated to the core utilities of the package
    on Sep 30, 2024
  5. locked and limited conversation to collaborators on Jan 17, 2025
  6. converted this issue into a discussion #683 on Jan 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    coreRelated to the core utilities of the package

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions