-
Notifications
You must be signed in to change notification settings - Fork 10.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[AutoDiff] Support differentiation of conditionals. #25057
Conversation
8dd1735
to
04b5e15
Compare
This is a work in-progress; there are at least two bugs.
|
- Support control flow in adjoint generation. - Make adjoint value mapping be per basic block. - Change `AdjointValue` to not be move-only. Original values from different basic blocks can share the same `AdjointValue`. - Propagate adjoint values from active basic block arguments to predecessor terminator operands. - Propagate adjoint values of active values to adjoint successor blocks. - Add runtime control flow differentiation tests.
04b5e15
to
fe1fbd8
Compare
Expose new crash in adjoint verification: ``` SIL verification failed: instruction isn't dominated by its operand: properlyDominates(valueI, I) ```
FYI: Since @dan-zheng is OOO, I'm taking over this today to make progress. |
Also fix `getRemappedTangentType` to handle addresses.
- Make adjoint buffer mapping per basic block. - For active buffers in original blocks, allocate and zero initialize adjoint buffers in adjoint entry. - Propagate adjoint buffers via `copy_addr` before branching in adjoint blocks. - Re-enable fixed tests.
Insert local allocations before previous local allocations to ensure that allocation and zero initialization instructions are grouped together. Fixes test/AutoDiff/generics.swift.
@@ -4216,11 +4216,15 @@ class AdjointEmitter final : public SILInstructionVisitor<AdjointEmitter> { | |||
} | |||
|
|||
SILBasicBlock::iterator getNextFunctionLocalAllocationInsertionPoint() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be better to turn this into a function that allocates a local buffer directly: ‘createFunctionLocalBuffer(SILType)’.
- Record *dominated* active values per basic block, not just active values used in basic blocks. - Remove `visitAllocStack` and `visitDeallocStack` from `AdjointEmitter`. - These fall out from active buffer handling. - Add nested conditional and recursion tests. - Remove "-differentiable-enable-control-flow" flag, now that limited control flow support seems robust.
5041a69
to
e74e43e
Compare
e74e43e
to
399b797
Compare
@swift-ci Please clean test tensorflow |
5b54584
to
0aaff91
Compare
@swift-ci Please test tensorflow |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I couldn't find any tests that are using var
s. I think mutation should be tested in order for this PR to be ready.
`var` tests currently crashing due to `AdjointEmitter` handling of `begin_access`/`end_access`.
0dc5580
to
806b464
Compare
- Change `AdjointEmitter` handling of `begin_access` and `end_access`. - Change `AdjointEmitter::getAdjointValue` of `begin_access` instruction to return adjoint buffer of the base buffer. Previously, it returned a `begin_access` of the adjoint base buffer, without generating a corresponding `end_access` instruction, leading to a hole. - Change `AdjointEmitter::visitBeginAccessInst` to generate no code, only performing verification and propagating cleanups. - Change `AdjointEmitter::visitEndAccessInst` to do nothing. - Fix and add `var` tests. - Todo: fix control-flow related memory leaks (FIXMEs) related to adjoint value/buffer propagation.
@swift-ci Please test tensorflow |
We peer programmed and discussed the two problems in depth. We found that Progress in 49937d9: Negative leak checking tests added to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM for merging as-is after existing issues are addressed. I’ll work on a fix for memory leaks.
- Make sure `gradient` calls test the right function. - Add struct `let` and `var` tests. Note: tuple/struct tests are designed to compute `x + x` (in convoluted ways) for easy verification. Corresponding tuple/struct tests have essentially the same body (e.g. `cond_nestedtuple_var` ~= `cond_nestedstruct_var`).
test/AutoDiff/leakchecking.swift
Outdated
} | ||
|
||
LeakCheckingTests.test("ControlFlow") { | ||
testWithLeakChecking(expectedLeakCount: 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This cond_tuple_var
test is not effective because it operates on Float
instead of Tracked<Float>
.
Fixing it requires significant changes to the Tracked
type. I'll fix and re-add it (and more tests) in a follow-up.
The control flow leakchecking tests below should be sufficient for testing memory leaks for now.
@swift-ci Please test tensorflow |
a467a11
to
cf8796e
Compare
@swift-ci Please test tensorflow |
@swift-ci please test tensorflow |
AdjointValue
to not be move-only. Original values fromdifferent basic blocks may share the same
AdjointValue
.terminator operands.
to predecessor blocks.
copy_addr
.AdjointEmitter
handling ofbegin_access
andend_access
.getAdjointValue
ofbegin_access
now returns the adjoint base buffer.Previously, it returned a
begin_access
of the adjoint base bufferwithout generating a corresponding
end_access
.AdjointEmitter::visitBeginAccessInst
now generates no code.AdjointEmitter::visitEndAccessInst
now does nothing.var
allocations (tuples, structs).Todos: