Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

`@grad` or `ChainRulesCore.rrule` with compiled tape?

Aperta
#187 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
35/100
Tipo di issue
Bug
Chiarezza
Abbastanza chiara
Stato di attività
Ferma
Stack tecnologico
julia
Ambito
tooling

Direzione di ricerca

Riproduci il comportamento segnalato usando ReverseDiff.GradientTape, ReverseDiff.compile e ReverseDiff.gradient! con gli esempi forniti di @grad e rrule. Traccia il modo in cui il tape compilato invoca il pullback personalizzato, quindi determina se dovrebbe usare l'input corrente invece del valore catturato durante la compilazione; il lavoro è completato quando il risultato compilato corrisponde alle derivate ricavate manualmente e a quelle di ForwardDiff per x2.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Is it possible to define a pullback via the ReverseDiff.@grad macro or a ChainRulesCore.rrule and use it with a compiled tape? When I try either approach with a simple function the pullback seems to remember the input value that was used when the tape was compiled. Is this expected?

Here's an example with @grad:

module ReverseDiffGradMacro

using ReverseDiff
using ForwardDiff

f1(x) = sin(x) + cos(x)

f1(x::ReverseDiff.TrackedReal) = ReverseDiff.track(f1, x)
ReverseDiff.@grad function f1(x::Real)
    xv = ReverseDiff.value(x)

    function f1_pullback(Δ)
        println("hello from @grad f1_pullback")
        return (Δ*(cos(xv) - sin(xv)),)
    end

    return f1(xv), f1_pullback
end

function doit()
    f1vec = X->f1(X[1])
    x = pi/6
    
    println("calculating gradient of f1vec, x = $x")
    dydx_hand = cos(x) - sin(x)
    dydx_rd1_notape = ReverseDiff.gradient(f1vec, [x])
    dydx_fd1 = ForwardDiff.gradient(f1vec, [x])
    @show dydx_hand dydx_fd1 dydx_rd1_notape
    
    println("calculating gradient of f1vec with compiled tape, x = $x")
    tape = ReverseDiff.GradientTape(f1vec, [x])
    compiled_tape = ReverseDiff.compile(tape)
    dydx_rd1_compiled = ReverseDiff.gradient!(compiled_tape, [x])
    @show dydx_rd1_compiled

    x2 = x + 0.1
    println("calculating gradient of f1vec with compiled tape, x = $x2")
    dydx_hand2 = cos(x2) - sin(x2)
    dydx_fd2 = ForwardDiff.gradient(f1vec, [x2])
    dydx_rd2_compiled = ReverseDiff.gradient!(compiled_tape, [x2])
    @show dydx_hand2 dydx_fd2 dydx_rd2_compiled

    return nothing
end

end # module

And here's an example with an rrule from ChainRulesCore:

module ReverseDiffChainRulesCore

using ChainRulesCore: NoTangent
import ChainRulesCore: rrule

using ReverseDiff
using ForwardDiff

f1(x) = sin(x) + cos(x)

function rrule(::typeof(f1), x)

    function f1_pullback(ybar)
        println("hello from rrule f1_pullback")
        return NoTangent(), ybar*(cos(x) - sin(x))
    end

    return f1(x), f1_pullback
end

ReverseDiff.@grad_from_chainrules f1(x::ReverseDiff.TrackedReal)

function doit()
    f1vec = X->f1(X[1])
    x = pi/6
    
    println("calculating gradient of f1vec, x = $x")
    dydx_hand = cos(x) - sin(x)
    dydx_rd1_notape = ReverseDiff.gradient(f1vec, [x])
    dydx_fd1 = ForwardDiff.gradient(f1vec, [x])
    @show dydx_hand dydx_fd1 dydx_rd1_notape
    
    println("calculating gradient of f1vec with compiled tape, x = $x")
    tape = ReverseDiff.GradientTape(f1vec, [x])
    compiled_tape = ReverseDiff.compile(tape)
    dydx_rd1_compiled = ReverseDiff.gradient!(compiled_tape, [x])
    @show dydx_rd1_compiled

    x2 = x + 0.1
    println("calculating gradient of f1vec with compiled tape, x = $x2")
    dydx_hand2 = cos(x2) - sin(x2)
    dydx_fd2 = ForwardDiff.gradient(f1vec, [x2])
    dydx_rd2_compiled = ReverseDiff.gradient!(compiled_tape, [x2])
    @show dydx_hand2 dydx_fd2 dydx_rd2_compiled

    return nothing
end

end # module

In both examples, dydx_rd2_compiled is a derivative calculated using a compiled tape with input value x2. It should be the same as dydx_hand2 and dydx_fd2, which are found using the actual expression for the derivative and ForwardDiff, respectively. But dydx_rd2_compiled actually matches all the previous derivatives calculated with input value x, which was used when the tape was compiled.

Any ideas?

Thanks!

Lingua principale
Julia
Stelle
397
Fork
62
Merge medio
12h 50m
PR unite (30g)
8

Preparare l'ambiente

Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di JuliaDiff/ReverseDiff.jl

Tutte le issue di JuliaDiff/ReverseDiff.jl

Issue simili

Altre issue su Julia

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.