Skip to content

[AutoDiff] Fix adjoints for loop-local active values #78374

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

Merged
merged 3 commits into from
Apr 15, 2025

Conversation

kovdan01
Copy link
Contributor

Fixes #78264

@kovdan01
Copy link
Contributor Author

Tagging @asl @JaapWijnen @rxwei

@kovdan01 kovdan01 marked this pull request as ready for review December 27, 2024 21:35
@kovdan01 kovdan01 requested a review from eeckstein as a code owner December 27, 2024 21:35
@asl
Copy link
Contributor

asl commented Dec 30, 2024

@swift-ci please test

@kovdan01 kovdan01 force-pushed the issue78264-new branch 2 times, most recently from 6960602 to f9bb221 Compare January 12, 2025 20:57
@asl
Copy link
Contributor

asl commented Jan 13, 2025

@swift-ci please test

@kovdan01
Copy link
Contributor Author

Would be glad to see feedback from everyone interested

@asl
Copy link
Contributor

asl commented Jan 15, 2025

@swift-ci please test

@kovdan01
Copy link
Contributor Author

Would be glad to see feedback from everyone interested

1 similar comment
@kovdan01
Copy link
Contributor Author

kovdan01 commented Feb 4, 2025

Would be glad to see feedback from everyone interested

@asl asl added the AutoDiff label Feb 13, 2025
@kovdan01
Copy link
Contributor Author

Would be glad to see feedback from everyone interested

1 similar comment
@kovdan01
Copy link
Contributor Author

Would be glad to see feedback from everyone interested

@clackary
Copy link

@kovdan01 I cherrypicked this change onto swift-DEVELOPMENT-SNAPSHOT-2025-02-20-a and built a toolchain. I used this toolchain to build all our internal swift projects, and everything builds successfully on macOS.

@asl asl requested a review from rxwei February 21, 2025 23:40
@asl
Copy link
Contributor

asl commented Feb 21, 2025

The change looks ok to me. The explanation of the problem is at #78264

Long story short: SSA values in the loop body should be considered as "new values" at each loop iteration. We used to reuse the adjoints for them before this patch (though we should create distinct adjoints on each loop iteration).

This used to work before due to a particular CFG generated for for-style loops. As a result we've been lucky and simply zeroed the adjoints in the loop header on each iteration (loop header BB was the first BB we encountered the adjoint, so it was initialized there and this zero-initialization happened on each loop iteration effectively producing new adjoint value).

However, this stopped to work for while-style loops as the CFG is different and while we produced adjoint initialization, it happened outside the loop and therefore the adjoint values got reused from the previous loop iteration.

@rxwei will you please take a look as a second pair of eyes? :)

@kovdan01
Copy link
Contributor Author

kovdan01 commented Feb 22, 2025

However, this stopped to work for while-style loops

To be a bit more precise: it not stopped working, it just never worked for repeat-while loops (if not never, at least, for several latest years). For regular while loops, we had the same situation that we observed with for loops, when the behavior looked correct because of a particular CFG.

@kovdan01
Copy link
Contributor Author

@kovdan01 I cherrypicked this change onto swift-DEVELOPMENT-SNAPSHOT-2025-02-20-a and built a toolchain. I used this toolchain to build all our internal swift projects, and everything builds successfully on macOS.

@clackary Great, thanks for letting me know! BTW, does "everything builds successfully on macOS" imply that your internal tests are also passing?

@clackary
Copy link

your internal tests are also passing?

@kovdan01 No, just the compile-time checks for now. Further testing is more of a manual process at the moment, but I can get to testing a few projects this week.

@kovdan01
Copy link
Contributor Author

kovdan01 commented Mar 6, 2025

@rxwei Could you please take a look at this PR? Thanks!

@clackary
Copy link

clackary commented Mar 6, 2025

@kovdan01 I was able to finish testing a bunch of our internal projects. The issue we discussed earlier was caused by a flaw in my invocation, so nothing to worry about there. This looks good from my end.

@kovdan01
Copy link
Contributor Author

@rxwei Could you please take a look at this PR? Thanks!

@asl
Copy link
Contributor

asl commented Apr 2, 2025

@swift-ci please smoke test

Copy link
Contributor

@asl asl left a comment

Choose a reason for hiding this comment

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

This LGTM module few asserts-related nits. Please fix them and I think we're good to go!

assert(!arrayValue && "Array value already found");
// The first `destructure_tuple` result is the `Array` value.
arrayValue = dti->getResult(0);
#ifdef NDEBUG
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider using ASSERT / DEBUG_ASSERT from swift/Basic/Assertions.h instead of conditional asserts, etc. Overall, the intention is to get rid of conditional asserts in new code (and avoid #ifdef NDEBUG).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've put this break; under DEBUG_ASSERT_enabled condition since having the check present increases iterations count and this should probably not be done in non-debug builds. Please let me know if this looks reasonable for you.

// invariants hold and then skip.
if (auto *ai = getAllocateUninitializedArrayIntrinsicElementAddress(
bbActiveValue)) {
#ifndef NDEBUG
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Deleted this preprocessor condition and switched to ASSERT. These checks should be OK in terms of negative performance impact, so ASSERT seems preferrable over DEBUG_ASSERT

continue;
}

assert(getTangentValueCategory(bbActiveValue) ==
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@asl As far as I understood, there is an intention to enable most checks in all builds including release ones. Given that, should I switch these and other remaining regular assert to ASSERT?

Copy link
Contributor

Choose a reason for hiding this comment

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

Let's switch while here, yes

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, see ddfc573

@kovdan01 kovdan01 requested a review from asl April 7, 2025 16:08
@asl
Copy link
Contributor

asl commented Apr 7, 2025

@swift-ci please test

1 similar comment
@asl
Copy link
Contributor

asl commented Apr 8, 2025

@swift-ci please test

@asl
Copy link
Contributor

asl commented Apr 15, 2025

@swift-ci please smoke test

@asl asl enabled auto-merge (squash) April 15, 2025 09:08
@asl asl merged commit 5d0bfed into swiftlang:main Apr 15, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Adjoint for active values in loops are just wrong
3 participants