Skip to content

[AutoDiff] Make @noDerivative attribute imply non-varying semantics. #29543

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 2 commits into from
Jan 31, 2020

Conversation

dan-zheng
Copy link
Contributor

Previously, @noDerivative could only be declared on stored properties in
Differentiable-conforming structs and classes.

Now, @noDerivative can be declared on all function-like declarations:
func, var, init, and subscript.

@noDerivative attribute now also implies @_semantics("autodiff.nonvarying").

SIL values produced from @noDerivative declarations will never be marked as
varying by differentiable activity analysis. These values do not need a
derivative.

Marking declarations as @noDerivative is a usability improvement over using
withoutDerivative(at:) at use sites. However, @noDerivative is invasive
because it requires annotation on original declarations. There may exist a more
elegant solution.


Example:

@differentiable
func sum(_ array: [Float]) -> Float {
  var result: Float = 0
  for i in array.indices {
    result = result + array[i]
  }
  return result
}

Array.indices calls the default protocol implementation RandomAccessCollection.indices, which is defined in the stdlib and currently has no differentiation-related annotations.

Thus, the code above triggers a non-differentiability error:

$ swift test.swift
test.swift:1:2: error: function is not differentiable
@differentiable
~^~~~~~~~~~~~~~
test.swift:2:6: note: when differentiating this function definition
func sum(_ array: [Float]) -> Float {
     ^
test.swift:4:18: note: cannot differentiate through a non-differentiable result; do you want to use 'withoutDerivative(at:)'?
  for i in array.indices {
                 ^

Old workaround: use withoutDerivative(at: array.indices. withoutDerivative(at:) has non-varying semantics.

@differentiable
func sum(_ array: [Float]) -> Float {
  var result: Float = 0
  for i in withoutDerivative(at: array.indices) {
    result = result + array[i]
  }
  return result
}
// No non-differentiability error.

However, applying withoutDerivative(at:) is cumbersome for properties/functions like Array.indices or Array.count, which are always expected to have non-varying semantics.

Example of excessive withoutDerivative(at:) usage: poor usability.


New workaround: annotate RandomAccessCollection.indices with @noDerivative. This is an alternative to applying withoutDerivative(at:), achieving the same effect.

@differentiable
func sum(_ array: [Float]) -> Float {
  var result: Float = 0
  for i in array.indices {
    result = result + array[i]
  }
  return result
}
// No non-differentiability error for original code.

Note that this patch does not actually add @noDerivative to RandomAccessCollection.indices in the stdlib. But adding @noDerivative to RandomAccessCollection.indices is verified to work.

Previously, `@noDerivative` could only be declared on stored properties in
`Differentiable`-conforming structs and classes.

Now, `@noDerivative` can be declared on all function-like declarations:
`func`, `var`, `init`, and `subscript`.

`@noDerivative` attribute now also implies `@_semantics("autodiff.nonvarying")`.

SIL values produced from `@noDerivative` declarations will never be marked as
varying by differentiable activity analysis. These values do not need a
derivative.

Marking declarations as `@noDerivative` is a usability improvement over using
`withoutDerivative(at:)` at use sites. However, `@noDerivative` is invasive
because it requires annotation on original declarations. There may exist a more
elegant solution.
@dan-zheng dan-zheng added the tensorflow This is for "tensorflow" branch PRs. label Jan 30, 2020
@dan-zheng
Copy link
Contributor Author

@swift-ci Please test tensorflow

@dan-zheng
Copy link
Contributor Author

@swift-ci Please test tensorflow

@dan-zheng dan-zheng merged commit 7551278 into swiftlang:tensorflow Jan 31, 2020
@dan-zheng dan-zheng deleted the noderivative-revamp branch January 31, 2020 00:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
tensorflow This is for "tensorflow" branch PRs.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants