Skip to content

[AutoDiff upstream] Introduce @differentiable attribute to mark functions as differentiable. #27506

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 16 commits into from
Nov 11, 2019

Conversation

bgogul
Copy link
Contributor

@bgogul bgogul commented Oct 2, 2019

This PR introduces @differentiable attribute to mark functions as differentiable. This PR only contains changes related to parsing the attribute. Type checking and other changes will be added in subsequent patches.

See https://github.com/apple/swift/pull/27506/files#diff-f3216f4188fd5ed34e1007e5a9c2490f for examples and tests for the new attribute.

@saeta
Copy link
Contributor

saeta commented Oct 3, 2019

@bgogul I think you might have forgotten to handle the switch at: https://github.com/apple/swift/pull/27506/files#diff-a99d62dc86d23321183dc044483cf2caR808

@rxwei
Copy link
Contributor

rxwei commented Oct 3, 2019

I think the only thing we need to upstream in AutoDiff.h for parsing @differentiable is ParsedAutoDiffParameterIndices.

saeta added a commit that referenced this pull request Oct 4, 2019
This PR introduces the `@transposing` attribute to mark functions as
transposing other functions. This PR only contains changes related to parsing
the attribute. Type checking and other changes will be added in subsequent
patches.

This work is related to the `@differentiable` attribute in #27506.
@bgogul bgogul force-pushed the upstream_differentiable_attr branch from 12c07b4 to 0429dbd Compare October 4, 2019 22:59
@bgogul bgogul force-pushed the upstream_differentiable_attr branch from 0429dbd to a9ac462 Compare October 14, 2019 17:25
@bgogul bgogul changed the title [WIP] [AutoDiff upstream] Introduce @differentiable attribute to mark functions as differentiable. [AutoDiff upstream] Introduce @differentiable attribute to mark functions as differentiable. Oct 14, 2019
@bgogul bgogul requested a review from DougGregor October 14, 2019 18:47
@rxwei
Copy link
Contributor

rxwei commented Oct 15, 2019

@DougGregor could you review this patch when you get a chance?

@bgogul bgogul force-pushed the upstream_differentiable_attr branch from 4a150b1 to f10459e Compare October 15, 2019 17:53
@rxwei
Copy link
Contributor

rxwei commented Oct 15, 2019

@swift-ci please smoke test

1 similar comment
@bgogul
Copy link
Contributor Author

bgogul commented Oct 15, 2019

@swift-ci please smoke test

@bgogul
Copy link
Contributor Author

bgogul commented Oct 16, 2019

@swift-ci please clean smoke test

@bgogul
Copy link
Contributor Author

bgogul commented Oct 16, 2019

@swift-ci please smoke test linux

@bgogul
Copy link
Contributor Author

bgogul commented Oct 24, 2019

@DougGregor, hold off review on this one. I will try to split it further so that it is a slightly more easier to review.

@bgogul bgogul removed the request for review from DougGregor October 24, 2019 22:07
@bgogul bgogul force-pushed the upstream_differentiable_attr branch from 51c32a8 to 608d6db Compare November 6, 2019 18:37
@bgogul
Copy link
Contributor Author

bgogul commented Nov 6, 2019

@swift-ci please smoke test

@dan-zheng dan-zheng requested a review from lattner November 7, 2019 21:38
DECL_ATTR(differentiable, Differentiable,
OnAccessor | OnConstructor | OnFunc | OnVar | OnSubscript | LongAttribute |
AllowMultipleAttributes |
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe this affects ABI, so I'd recommend removing the "ABIStableToAdd | ABIStableToRemove" tags, as well as APIStableToRemove which seems inappropriate.

Copy link
Contributor

Choose a reason for hiding this comment

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

It's not clear to me what these tags mean exactly, but I'll try the following configuration on tensorflow branch to see if things break:

ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIBreakingToRemove

Testing on tensorflow branch in #28148. The PR description has more context.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Replaced the attributes to be similar to tensorflow branch.

Copy link
Contributor

@lattner lattner left a comment

Choose a reason for hiding this comment

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

looks great with some changes requested, thanks!

#define SWIFT_AST_AUTODIFF_H

#include "ASTContext.h"
#include "llvm/ADT/SmallBitVector.h"
Copy link
Contributor

Choose a reason for hiding this comment

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

SmallBitVector.h looks unused.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, is ASTContext.h necessary here? Can you forward declare or include smaller headers? ASTContext.h includes the world.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for catching these. It turned out, I only needed IndexSubset.h instead of ASTContext.h

return V.Ordered.Index;
}

enum Kind getKind() const {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: s/enum Kind/Kind/

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.

@@ -907,6 +907,18 @@ bool Parser::parseMatchingToken(tok K, SourceLoc &TokLoc, Diag<> ErrorDiag,
return false;
}

bool Parser::parseUnsignedInteger(unsigned &Result, SourceLoc &Loc,
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do you need this new method? DAK_Alignment handling in ParseDecl.cpp does this:

StringRef alignmentText = Tok.getText();
unsigned alignmentValue;
if (alignmentText.getAsInteger(0, alignmentValue)) {
diagnose(Loc, diag::alignment_must_be_positive_integer);
return false;
}

Won't this work for you at the callsite?

Copy link
Contributor

Choose a reason for hiding this comment

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

If you're trying to introduce a new generally useful utility, I'd recommend doing that as a separate patch which also migrates the existing callsites to it.

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 found the code snippet similar to DAK_Alignment in a bunch of places. I agree it is better to introduce this in a separate PR. I will do so shortly.

There are also more uses of parseUnsignedInteger in the AD code base that has not been upstreamed yet.

// Check that token after comma is 'wrt:' or a function specifier label.
if (!Tok.is(tok::identifier) || !(Tok.getText() == "wrt" ||
Tok.getText() == "jvp" ||
Tok.getText() == "vjp")) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it help to have a function like:

enum { wrt, jvp, vjp, invalid } classifyLabel(StringRef str);

function to keep all the classification logic in sync, and move the magic string parsing into a single place?

Copy link
Contributor

Choose a reason for hiding this comment

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

“jvp:” and “vjp:” will go away very soon with the almost-finished retroactive derivative registration feature (‘@differentiating’). So I think it is fine to leave them as is!

Copy link
Contributor

Choose a reason for hiding this comment

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

Good to know, but it is important to keep master consistent and following best practices. If these aren't important, then it would be fine to remove them from the patch. If they need to be in the patch, then please consider implementing them in a nice way :).

I'm not saying that classifyLabel is an appropriate thing, just saying that the rationale doesn't make sense.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, sounds good!

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 have added a bunch of helpers. PTAL.

(Although other code in master is using Tok.getText() to compare against literal strings.)

funcDiag, /*allowOperators=*/true,
/*allowZeroArgCompoundNames=*/true);
// If no trailing comma or 'where' clause, terminate parsing arguments.
if (Tok.isNot(tok::comma) && Tok.isNot(tok::kw_where))
Copy link
Contributor

Choose a reason for hiding this comment

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

Tok.isNot takes multiple arguments, please use that instead of && here and anywhere else this comes up.

@@ -0,0 +1,180 @@
// RUN: %target-swift-frontend -parse -verify %s

/// Good
Copy link
Contributor

Choose a reason for hiding this comment

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

nice, thank you for the testcases!

Copy link
Contributor Author

@bgogul bgogul left a comment

Choose a reason for hiding this comment

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

Thanks for the review, Chris!

@@ -907,6 +907,18 @@ bool Parser::parseMatchingToken(tok K, SourceLoc &TokLoc, Diag<> ErrorDiag,
return false;
}

bool Parser::parseUnsignedInteger(unsigned &Result, SourceLoc &Loc,
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 found the code snippet similar to DAK_Alignment in a bunch of places. I agree it is better to introduce this in a separate PR. I will do so shortly.

There are also more uses of parseUnsignedInteger in the AD code base that has not been upstreamed yet.

return V.Ordered.Index;
}

enum Kind getKind() const {
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.

#define SWIFT_AST_AUTODIFF_H

#include "ASTContext.h"
#include "llvm/ADT/SmallBitVector.h"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for catching these. It turned out, I only needed IndexSubset.h instead of ASTContext.h

// Check that token after comma is 'wrt:' or a function specifier label.
if (!Tok.is(tok::identifier) || !(Tok.getText() == "wrt" ||
Tok.getText() == "jvp" ||
Tok.getText() == "vjp")) {
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 have added a bunch of helpers. PTAL.

(Although other code in master is using Tok.getText() to compare against literal strings.)

DECL_ATTR(differentiable, Differentiable,
OnAccessor | OnConstructor | OnFunc | OnVar | OnSubscript | LongAttribute |
AllowMultipleAttributes |
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Replaced the attributes to be similar to tensorflow branch.

@lattner
Copy link
Contributor

lattner commented Nov 10, 2019

LGTM.

@rxwei
Copy link
Contributor

rxwei commented Nov 10, 2019

@swift-ci please smoke test

1 similar comment
@rxwei
Copy link
Contributor

rxwei commented Nov 10, 2019

@swift-ci please smoke test

@rxwei
Copy link
Contributor

rxwei commented Nov 11, 2019

@swift-ci please smoke test macOS

@bgogul
Copy link
Contributor Author

bgogul commented Nov 11, 2019

@swift-ci please smoke test

@rxwei rxwei merged commit 5accda2 into swiftlang:master Nov 11, 2019
@gottesmm
Copy link
Contributor

This broke the build. Please when doing these larger sorts of changes use a full test.

@gottesmm
Copy link
Contributor

@dan-zheng
Copy link
Contributor

dan-zheng commented Nov 12, 2019

This broke the build. Please when doing these larger sorts of changes use a full test.

Sorry about that! We'll be sure to use @swift-ci Please test on all PRs in the future.
The error appears to be that SwiftSyntax sources need to be regenerated:

01:37:13 --- 5067 ----
01:37:13 diff -r -x '.*' --context=0 /var/folders/_8/79jmzf2142z2xydc_01btlx00000gn/T/tmpvgMewm/syntax_nodes/SyntaxNodes.swift /Users/buildnode/jenkins/workspace/swift-PR-osx/branch-master/swift-syntax/Sources/SwiftSyntax/gyb_generated/syntax_nodes/SyntaxNodes.swift
01:37:13 *** /var/folders/_8/79jmzf2142z2xydc_01btlx00000gn/T/tmpvgMewm/syntax_nodes/SyntaxNodes.swift	Tue Nov 12 01:37:13 2019
01:37:13 --- /Users/buildnode/jenkins/workspace/swift-PR-osx/branch-master/swift-syntax/Sources/SwiftSyntax/gyb_generated/syntax_nodes/SyntaxNodes.swift	Mon Nov 11 23:53:23 2019
01:37:13 ***************
01:37:13 *** 6904,7844 ****
01:37:13 - // MARK: - DifferentiableAttributeArgumentsSyntax
01:37:13 - 
01:37:13 - /// 
01:37:13 - /// The arguments for the `@differentiable` attribute: an optional          differentiation parameter list and associated functions.
01:37:13 - /// 
01:37:13 - public struct DifferentiableAttributeArgumentsSyntax: SyntaxProtocol, SyntaxHashable {
01:37:13 -   enum Cursor: Int {
01:37:13 -     case diffParams
01:37:13 -     case diffParamsComma
01:37:13 -     case maybePrimal
01:37:13 -     case maybeAdjoint
01:37:13 -     case maybeJVP
01:37:13 -     case maybeVJP
01:37:13 -     case whereClause
01:37:13 -   }
...
01:37:13 FAIL: Gyb-generated files committed to repository do not match generated ones. Please re-generate the gyb-files and recommit them.

I'm taking a look into the issue now. @gottesmm: would you prefer that we revert this PR in the meantime?

EDIT: swift-syntax fix in swiftlang/swift-syntax#178.

dan-zheng added a commit to dan-zheng/swift-syntax that referenced this pull request Nov 12, 2019
dan-zheng added a commit to dan-zheng/swift-syntax that referenced this pull request Nov 12, 2019
Update gyb-generated files for `@differentiable` attribute.
Friend PR: swiftlang/swift#27506
@atrick
Copy link
Contributor

atrick commented Nov 12, 2019

@dan-zheng @gottesmm PR size has nothing to do with it. Any functional change that could conceivably be sensitive to build configuration needs to run normal PR testing (swift-ci test). I always run normal testing on a functional change, but a lot of people aren't doing this.

For a major functional change full PR testing would include benchmarks, SCK, and maybe even compiler performance tests.

@beccadax
Copy link
Contributor

@dan-zheng I noticed today that this PR includes serialization for @differentiable, but there doesn't seem to be any deserialization code that uses DifferentiableDeclAttrLayout, even now. Is this intentional?

@dan-zheng
Copy link
Contributor

dan-zheng commented Dec 19, 2019

@dan-zheng I noticed today that this PR includes serialization for @differentiable, but there doesn't seem to be any deserialization code that uses DifferentiableDeclAttrLayout, even now. Is this intentional?

Thanks for noticing!

@differentiable attribute (de)serialization is currently not fully done because it's ~blocked by @differentiable attribute type-checking, which hasn't yet been upstreamed to master from tensorflow branch. One of the serialized components (IndexSubset * representing parameter indices) is resolved by @differentiable attribute type-checking.

TF-836 tracks @differentiable attribute serialization. There's a NOTE comment in the source code referencing TF-836.


Small aside: @differentiable attribute has a bunch of components and not all of them are serialized. For example:

  • Not serialized
  • Serialized
    • The resolved parameter indices (IndexSubset *). Resolving parameter indices is not particularly cheap, so serializing them seemed sensible.
    • The resolved JVP/VJP derivative function declarations (FuncDecl *).

†: Serializing this is necessary to print deserialized @differentiable attributes exactly like how they were written in source code. We didn't prioritize full fidelity printing, so we left this unserialized.

It's worthwhile to discuss which attribute components should be serialized! I started a forum question for discussion.

Precedent: DynamicReplacementAttr is similar to DifferentiableAttr/DerivativeAttr/TransposeAttr in that it also stores a DeclNameRef. For DynamicReplacementAttr, all DeclNameRef components are serialized.

dan-zheng added a commit to dan-zheng/swift-syntax that referenced this pull request Apr 8, 2020
Update gyb-generated files for `@differentiable` attribute.
Friend PR: swiftlang/swift#27506
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants