-
Notifications
You must be signed in to change notification settings - Fork 125
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
Differentiate for loop condition expression #818
Conversation
clang-tidy review says "All clean, LGTM! 👍" |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #818 +/- ##
==========================================
+ Coverage 93.95% 93.98% +0.03%
==========================================
Files 55 55
Lines 7967 8009 +42
==========================================
+ Hits 7485 7527 +42
Misses 482 482
... and 1 file with indirect coverage changes
|
Can you add tests? |
yeah have added the same test case mentioned in the issue. Will that be alright ? |
clang-tidy review says "All clean, LGTM! 👍" |
clang-tidy review says "All clean, LGTM! 👍" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The solution needs to be corrected. The for-loop condition
should be differentiated in each iteration.
The solution in this pull-request generates incorrect derivative for the example show below:
#include "clad/Differentiator/Differentiator.h"
#include <iostream>
#define show(x) std::cout << #x << ": " << x << "\n";
double fn(double i, double j) {
double res = 0;
for (int c = 0; (res += i * j); ++c) {
if (c == 2)
break;
}
return res;
}
int main() {
auto fn_grad = clad::gradient(fn);
double u = 3, v = 5;
double du = 0, dv = 0;
fn_grad.execute(u, v, &du, &dv);
show(du);
show(dv);
}
Output
du: 5
dv: 3
Expected Output
du: 10
dv: 6
Oh right ok, will fix this |
hi @parth-07 for c == 2 condition du and dv will be 15 and 9 right ? cause the loop will run 3 times. |
Oh, yes. You are right. |
hi @parth-07, I have added the differentiation of condition inside the loop body and also at the end of the loop. This is done because for the value where condition is false, the condition is exeucted but the loop body is not executed. So we need to add a extra differentiation step after loop body. This does not seem to be working for when we break at 1st or 2nd iteration and I am not able to understand why exactly. Can you just help me out here ? Also is this the right approach here ? This is the function being differentiated
Output: Expected: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-tidy made some suggestions
if (FS->getCond()) | ||
cond = Visit(FS->getCond()); | ||
std::tie(condDiff, condExprDiff) = DifferentiateSingleExpr(FS->getCond()); | ||
std::tie(condDiffOuter, condExprDiffOuter) = DifferentiateSingleExpr(FS->getCond()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: misleading indentation; statement is not part of the previous 'if' [clang-diagnostic-misleading-indentation]
std::tie(condDiffOuter, condExprDiffOuter) = DifferentiateSingleExpr(FS->getCond());
^
Additional context
lib/Differentiator/ReverseModeVisitor.cpp:1069: previous statement is here
if (FS->getCond())
^
if (FS->getCond()) | ||
cond = Visit(FS->getCond()); | ||
std::tie(condDiff, condExprDiff) = DifferentiateSingleExpr(FS->getCond()); | ||
std::tie(condDiffOuter, condExprDiffOuter) = DifferentiateSingleExpr(FS->getCond()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: misleading indentation: statement is indented too deeply [readability-misleading-indentation]
std::tie(condDiffOuter, condExprDiffOuter) = DifferentiateSingleExpr(FS->getCond());
^
Additional context
lib/Differentiator/ReverseModeVisitor.cpp:1069: did you mean this line to be inside this 'if'
if (FS->getCond())
^
5801e5a
to
728c53e
Compare
clang-tidy review says "All clean, LGTM! 👍" |
|
clang-tidy review says "All clean, LGTM! 👍" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I differentiated cond twice adding one inside the loop and one outside the loop
This is correct.
The below example gives wrong result:
#include "clad/Differentiator/Differentiator.h"
#include <iostream>
#define show(x) std::cout << #x << ": " << x << "\n";
double fn(double i, double j) {
double res = 0;
for (int c = 0; true && (res += i * j); ++c) {
if (c == 0)
break;
}
return res;
}
int main() {
auto fn_grad = clad::gradient(fn);
double u = 3, v = 5;
double du = 0, dv = 0;
fn_grad.execute(u, v, &du, &dv);
show(du);
show(dv);
}
@rohanjulka19, can you take a look at the comment and possibly make progress here? |
Hi @vgvassilev , yeah sorry should have acknowledged here, I had seen the comment. I am currently working on adding && operator support in the VisitBinaryOperator function it's just that I am facing a issue that I haven't figured out how to solve. Basically for expression a && b && c it needs to have concentric if conditions i.e if(a) { df/da if(b) {df/db} } but since we start parsing from rightmost expression I am unable to add the right hand side expression's differentiation inside the IF block of the left expression as I am not sure how to pass it to the left hand side expression when visiting the LHS expression. So was just figuring that out plus I had university work so wasn't able to give it much time, I will try to push it today by end of day (GMT+1). |
Is that work in the context of gsoc and if so, can you send me an email? |
I have sent you an email |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-tidy made some suggestions
@@ -576,6 +575,8 @@ | |||
clang::Expr* CreateCFTapePushExpr(std::size_t value); | |||
|
|||
public: | |||
const bool m_IsInvokedBySwitchStmt = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: member 'm_IsInvokedBySwitchStmt' of type 'const bool' is const qualified [cppcoreguidelines-avoid-const-or-ref-data-members]
const bool m_IsInvokedBySwitchStmt = false;
^
@@ -576,6 +575,8 @@ | |||
clang::Expr* CreateCFTapePushExpr(std::size_t value); | |||
|
|||
public: | |||
const bool m_IsInvokedBySwitchStmt = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: member variable 'm_IsInvokedBySwitchStmt' has public visibility [cppcoreguidelines-non-private-member-variables-in-classes]
const bool m_IsInvokedBySwitchStmt = false;
^
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-tidy made some suggestions
@@ -576,6 +575,8 @@ namespace clad { | |||
clang::Expr* CreateCFTapePushExpr(std::size_t value); | |||
|
|||
public: | |||
bool m_IsInvokedBySwitchStmt = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: member variable 'm_IsInvokedBySwitchStmt' has public visibility [cppcoreguidelines-non-private-member-variables-in-classes]
bool m_IsInvokedBySwitchStmt = false;
^
2777d90
to
e604ae7
Compare
Now in both forward and reverse pass, the condition check happens inside the loop body after the loop condition diff statements are executed. So now the order in which loop executes is -
This is done to ensure the condition diff executes one additional time when the loop condition fails right before the loop exits. Additionaly this handles the scenario where the forward pass loop terminates due to break stmt in that case in reverse pass for the first iteration loop cond diff is not executed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the pull-request. Overall, the changes seem good. I will need some more time to review the pull-request in detail.
1f4a7e6
to
ff1d72f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes looks good. Can you please update the 'test/CUDA/GradientCuda.cu' test?
I have updated the Cuda test now it is passing. Can't seem to figure out why a test case is not working on x86, it's working on my laptop. |
@MihailMihov, this failure seems to be similar to what you've been hunting down? |
Seems like it's the same thing, in fact I'm not sure if one of the numbers isn't the exact same that I got somewhere. I'll see whether it happens on my machine too, like the other issue. |
Well I checked out your branch, but it seems like the issue is different. I had a really stupid error (uninitialized variable in my test). I ran your test with LLVM's MemorySanitizer and there is an uninitialized value here too, but it seems to be coming from one of the tapes.
In order to see a more detailed stack trace I'd need to compile clad instrumented with MSan, but I couldn't figure it out today, I'll try to get you a better stack trace tomorrow. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-tidy made some suggestions
ok thanks to @MihailMihov, turns out there was a variable which wasn't initialised and was causing the test to fail. Now that it is initialised to zero, the test is passing. The variable is _d_cond which is added to ensure that while differentiating expression containing && operator, the expression which is then assigned to the cond variable gets differentiated.
@MihailMihov Not sure if this is related to the warning you caught. |
This change differentiates the loop condition expression. Additionaly if in forward pass a loop terminates pre-maturely due to break stmt. The reverse pass should start differentiation with break statment and not the loop condition differentiation. This change keeps track of whether the break was called in forward pass and based on that in reverse mode it is decided whether the loop differentiation is skipped for the first iteration or not.
I just tried running the memory sanitizer with your new changes and the warning is gone, so that was likely the issue. |
Fixes #746 - Incorrect differentiation of loop conditions in reverse mode