Skip to content
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

[SR-14057] Implement Collection.differentiableReduce #55254

Open
dan-zheng opened this issue May 13, 2020 · 2 comments
Open

[SR-14057] Implement Collection.differentiableReduce #55254

dan-zheng opened this issue May 13, 2020 · 2 comments
Labels
AutoDiff compiler The Swift compiler in itself

Comments

@dan-zheng
Copy link
Collaborator

Previous ID SR-14057
Radar None
Original Reporter @dan-zheng
Type Sub-task
Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Sub-task
Assignee None
Priority Medium

md5: 99f51c59606b6059ec9f1e4b34a6280a

Parent-Task:

  • SR-14056 Generalize Array: Differentiable conformance to more Collection types

Issue Description:

Generalize Array.differentiableReduce to an appropriately constrained Collection.differentiableReduce function.

It's not currently possible to write code (e.g. using loops) to implement reduction over a Differentiable-conforming Collection type otherwise.

Some code adapted from Array.differentiableReduce:

extension Collection
where
  Self: Differentiable, Element: Differentiable,
  TangentVector: MutableCollection,
  TangentVector.Element == Element.TangentVector
{
  @differentiable(wrt: (self, initialResult))
  public func differentiableReduce<Result: Differentiable>(
    _ initialResult: Result,
    _ nextPartialResult: @differentiable (Result, Element) -> Result
  ) -> Result {
    reduce(initialResult, nextPartialResult)
  }

  @inlinable
  @derivative(of: differentiableReduce)
  internal func _vjpDifferentiableReduce<Result: Differentiable>(
    _ initialResult: Result,
    _ nextPartialResult: @differentiable (Result, Element) -> Result
  ) -> (
    value: Result,
    pullback: (Result.TangentVector)
      -> (TangentVector, Result.TangentVector)
  ) {
    var pullbacks:
      [(Result.TangentVector) -> (Result.TangentVector, Element.TangentVector)] =
        []
    let count = self.count
    pullbacks.reserveCapacity(count)
    var result = initialResult
    for element in self {
      let (y, pb) =
        valueWithPullback(at: result, element, in: nextPartialResult)
      result = y
      pullbacks.append(pb)
    }
    return (
      value: result,
      pullback: { [selfTan = zeroTangentVector] tangent in
        var selfTangent = selfTan
        var resultTangent = tangent
        var index = selfTangent.startIndex
        for pullback in pullbacks.reversed() {
          let (newResultTangent, elementTangent) = pullback(resultTangent)
          resultTangent = newResultTangent
          selfTangent[index] += elementTangent
          index = selfTangent.index(after: index)
        }
        return (selfTangent, resultTangent)
      }
    )
  }
}
// Example:
@differentiable
func foo(_ array: [Float]) -> Float {
  return array.differentiableReduce(0, +)
}
print(gradient(at: [1, 2, 3, 4], in: foo))

// Doesn't currently work because `Array.TangentVector` is not a `MutableCollection`.

We need to change array-specific code to use general differentiation helpers, like AdditiveArithmetic.+.
One roadblock may be converting [Element.TangentVector] to Self.TangentVector in the pullback body. I'm not sure how to best do this.

@philipturner
Copy link
Contributor

@dan-zheng the second code sample in this report's description seems to work. I tried this and got the following output:

import _Differentiation

@differentiable(reverse)
func foo(_ array: [Float]) -> Float {
  return array.differentiableReduce(0, +)
}
print(gradient(at: [1, 2, 3, 4], of: foo))
[1.0, 1.0, 1.0, 1.0]

Could you provide another sample that's broken by the problem you referenced?

@dan-zheng
Copy link
Collaborator Author

The second code snippet works as is because differentiableReduce is currently defined as a method on Array.

This issue tracks removing Array.differentiableReduce from the Differentiation library and generalizing it to Collection.differentiableReduce, as prototyped in the first snippet. When this is done, I believe the second snippet fails to compile with the error in the issue description.

This can be verified by renaming the definition and usage differentiableReduce to something else in both snippets, e.g. differentiableReduce_.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
AutoDiff compiler The Swift compiler in itself
Projects
None yet
Development

No branches or pull requests

3 participants