How to register gradient metadata? #1749
-
According to https://enzyme.mit.edu/getting_started/CallingConvention/#custom-gradients one could give functions a custom gradient by attaching two pieces of metadata, however the example is in IR only and I would like to do it in C. This could be extremely useful in various circumstances, obviously. In my case, I am using external libraries such as GSL which already have corresponding derivative invocations which I can use to define the appropriate gradients. I tried defining a Is this at all possible in C or should I resign to either manually edit the IR or compile GSL with Enzyme? |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 4 replies
-
It is indeed (and the magic named global is the easiest way to do so right now in C++, though we are hoping to add function attribute in the future). Maybe share your code and we can see what's going awry? |
Beta Was this translation helpful? Give feedback.
-
Thanks a lot for providing this example and sorry for how long it took me to respond. I am very puzzled by this example. First, I am not sure why you are defining
And that leads me to my second puzzlement: what is this additional argument And finally, the Finally, even doing all of this, the program still returns 40 in both cases, rather than 60 as I would expect from my custom derivative in which I am intentionally using a wrong derivative... so that puzzles me even more. This is with LLVM v18.1.1 and Enzyme v0.0.103 and the compilation lines are
PS: not sure I should, but with the same versions, my original version still compiles and works incorrectly, rather than spitting the error message you mentioned |
Beta Was this translation helpful? Give feedback.
-
Sorry, yeah completely missed this. And custom rules definitely need better (or rather any C++) docs. We're currently adding a bunch of nice c++ sugar, so hopefully we'll add after that. The Julia custom rules docs is similar (but obviously julia not c++), but still can explain a bit what's happening: https://enzyme.mit.edu/index.fcgi/julia/stable/generated/custom_rule/#Defining-a-reverse-mode-rule . The CUDA guide also does this for CUDA/C++ but is more about the heterogeneity than the custom rules (https://enzyme.mit.edu/getting_started/CUDAGuide/). In reverse mode (where you're defining your rule), the three functions are: the function to overload, a function to replace the original function with in the forward pass, the backwards pass, in that order. The reason why the second function is necessary, is to save any data that may be overwritten but required in the reverse pass. For example, from the CUDA guide the aug_kern function cudaMalloc's memory to save data needed for the backwards pass: void* aug_kern(float* src, float* dsrc, float* dst, float* ddst) {
void** tape;
cudaMalloc(&tape, sizeof(void*) * /*total number of threads*/100);
aug_collide<<<1, 100>>>(src, dsrc, dst, ddst, tape);
return (void*)tape;
}
This is what As for the additional argument to the reverse pass. For functions that return an immutable, differentiated value (e.g. double) that additional variable is the partial derivative seed which we are back propagating to the reverse pass. For example, consider performing |
Beta Was this translation helpful? Give feedback.
-
and yeah @davidedelvento I didn't get a notifiaction so feel free to @ me in the future (@ 'ing you now for the same reason). |
Beta Was this translation helpful? Give feedback.
-
@wsmoses Thank you very much for your patience, understanding and helpful explanation. I am still an Enzyme newbie, but I am learning its abilities and how to use it and I really like it. Everything you said makes perfect sense, however even the corrected example did not work as expected when I compiled as I described it above. I was able to figure out the missing piece myself digging into the integration tests and their builing scripts (particularly The program started working when I compiled as follows
Of course in this example I could have avoided the separate linking step and using only ClangEnzyme, but I need that since I will move to multisource immediately after. I will be happy to make a PR including this contrived example, or the invsqrt in https://enzyme.mit.edu/getting_started/CallingConvention/#custom-gradients (or somewhere else) if you think it's appropriate. |
Beta Was this translation helpful? Give feedback.
Here is a corrected version of your code: