Skip to content

Commit 519236c

Browse files
authored
[AutoDiff] Add loop differentiation negative testcases. (#27796)
Loop differentiation produces incorrect results when the reduction accumulation variable is not initialized with an active parameter, e.g. when using `var result = 1` instead of `var result = x`. ``` func for_loop_nonactive_initial_value(_ x: Float) -> Float { var result: Float = 1 for _ in 0..<2 { result = result * x } return result } print(valueWithGradient(at: 3, in: for_loop_nonactive_initial_value)) // Actual: (value: 9.0, gradient: 3.0) // Expected: (value: 9.0, gradient: 6.0) ``` TF-933 tracks this issue. This patch add negative testcases (currently failing). Workarounds are to rewrite using `var result = x` or by using `Array.differentiableReduce`.
1 parent 7e0faeb commit 519236c

File tree

1 file changed

+26
-12
lines changed

1 file changed

+26
-12
lines changed

test/AutoDiff/control_flow.swift

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -522,18 +522,32 @@ ControlFlowTests.test("Enums") {
522522
ControlFlowTests.test("Loops") {
523523
func for_loop(_ x: Float) -> Float {
524524
var result = x
525-
for _ in 1..<3 {
525+
for _ in 0..<2 {
526526
result = result * x
527527
}
528528
return result
529529
}
530530
expectEqual((8, 12), valueWithGradient(at: 2, in: for_loop))
531531
expectEqual((27, 27), valueWithGradient(at: 3, in: for_loop))
532532

533+
func for_loop_nonactive_initial_value(_ x: Float) -> Float {
534+
var result: Float = 1
535+
for _ in 0..<2 {
536+
result = result * x
537+
}
538+
return result
539+
}
540+
// TODO(TF-933): Fix incorrect derivatives when `var result` is not initially
541+
// assigned to `x`.
542+
// expectEqual((4, 4), valueWithGradient(at: 2, in: for_loop_nonactive_initial_value))
543+
// expectEqual((9, 6), valueWithGradient(at: 3, in: for_loop_nonactive_initial_value))
544+
expectEqual((4, 2), valueWithGradient(at: 2, in: for_loop_nonactive_initial_value))
545+
expectEqual((9, 3), valueWithGradient(at: 3, in: for_loop_nonactive_initial_value))
546+
533547
func while_loop(_ x: Float) -> Float {
534548
var result = x
535-
var i = 1
536-
while i < 3 {
549+
var i = 0
550+
while i < 2 {
537551
result = result * x
538552
i += 1
539553
}
@@ -544,11 +558,11 @@ ControlFlowTests.test("Loops") {
544558

545559
func repeat_while_loop(_ x: Float) -> Float {
546560
var result = x
547-
var i = 1
561+
var i = 0
548562
repeat {
549563
result = result * x
550564
i += 1
551-
} while i < 3
565+
} while i < 2
552566
return result
553567
}
554568
// FIXME(TF-584): Investigate incorrect (too big) gradient values
@@ -586,12 +600,12 @@ ControlFlowTests.test("Loops") {
586600

587601
func nested_loop1(_ x: Float) -> Float {
588602
var outer = x
589-
for _ in 1..<3 {
603+
for _ in 0..<2 {
590604
outer = outer * x
591605

592606
var inner = outer
593-
var i = 1
594-
while i < 3 {
607+
var i = 0
608+
while i < 2 {
595609
inner = inner + x
596610
i += 1
597611
}
@@ -604,11 +618,11 @@ ControlFlowTests.test("Loops") {
604618

605619
func nested_loop2(_ x: Float, count: Int) -> Float {
606620
var outer = x
607-
outerLoop: for _ in 1..<count {
621+
outerLoop: for _ in 0..<count {
608622
outer = outer * x
609623

610624
var inner = outer
611-
var i = 1
625+
var i = 0
612626
while i < count {
613627
inner = inner + x
614628
i += 1
@@ -623,8 +637,8 @@ ControlFlowTests.test("Loops") {
623637
}
624638
return outer
625639
}
626-
expectEqual((24, 12), valueWithGradient(at: 2, in: { x in nested_loop2(x, count: 5) }))
627-
expectEqual((16, 8), valueWithGradient(at: 4, in: { x in nested_loop2(x, count: 5) }))
640+
expectEqual((24, 12), valueWithGradient(at: 2, in: { x in nested_loop2(x, count: 4) }))
641+
expectEqual((16, 8), valueWithGradient(at: 4, in: { x in nested_loop2(x, count: 4) }))
628642
}
629643

630644
runAllTests()

0 commit comments

Comments
 (0)