Skip to content

Commit 1f07901

Browse files
mcabbottToucheSir
andauthored
Expand limitations page of docs (#1298)
* add known bugs to limitations * Accessors * Apply suggestions from code review Co-authored-by: Brian Chen <[email protected]> Co-authored-by: Brian Chen <[email protected]>
1 parent 2edc190 commit 1f07901

File tree

1 file changed

+53
-7
lines changed

1 file changed

+53
-7
lines changed

docs/src/limitations.md

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
# Limitations
1+
# Design Limitations
22

3-
Zygote aims to support differentiating any code you might write in Julia, but it still has a few limitations. Notably, you might encounter errors when trying to differentiate:
4-
- array mutation
5-
- `try`/`catch` statements
6-
- "foreign call" expressions
3+
Zygote aims to support differentiating any Julia code, but it still has a few limitations.
4+
Notably, you might encounter errors when trying to differentiate:
5+
- array mutation,
6+
- `try`/`catch` statements,
7+
- "foreign call" expressions.
78

8-
In this section, we will introduce examples where each of these errors occurs as well as possible work-arounds.
9+
This section gives examples where each of these errors occurs, as well as possible work-arounds.
10+
11+
Below, it also describes some known bugs in expressions Zygote ought to be able to handle.
912

1013
## Array mutation
1114

@@ -123,7 +126,7 @@ Stacktrace:
123126
```
124127
`jclock` will multiply the result of our C function by an argument. When we try to differentiate with respect to this argument, we get an `foreigncall` error.
125128

126-
## Solutions
129+
# Solutions
127130

128131
For all of the errors above, the suggested solutions are similar. You have the following possible work arounds available (in order of preference):
129132
1. avoid the error-inducing operation (e.g. do not use mutating functions)
@@ -148,3 +151,46 @@ julia> gradient(jclock, rand())
148151
```
149152

150153
Lastly, if the code causing problems can be fixed, but it is package code instead of your code, then you should open an issue. For functions built into Julia or its standard libraries, you can open an issue with Zygote.jl or ChainRules.jl. For functions in other packages, you can open an issue with the corresponding package issue tracker.
154+
155+
156+
# Known Issues
157+
158+
Zygote's issue tracker has the current list of open [bugs](https://github.com/FluxML/Zygote.jl/issues?q=is%3Aissue+is%3Aopen+label%3Abug). There are some general principles about things you may wish to avoid if you can:
159+
160+
## `mutable struct`s
161+
162+
Zygote has limited support for mutation, and in particular will allow you to change a field in some `mutable struct X; a; b; end` by setting `x.a = val`.
163+
164+
However, this has [many limitations](https://github.com/FluxML/Zygote.jl/issues?q=is%3Aissue+is%3Aopen+mutable+struct) and should be avoided if possible.
165+
166+
The simple solution is to use only immutable `struct`s.
167+
168+
If you need to modify them, using something like `@set` from [Accessors.jl](https://github.com/JuliaObjects/Accessors.jl) should work well. This returns a new object, but does not have side-effects on other copies of it.
169+
170+
## Re-using variable names
171+
172+
It is common to accumulate values in a loop by re-binding the same variable name to a new value
173+
many times, for example:
174+
```
175+
function mysum(x::Real, n::Int)
176+
tot = 0.0
177+
for i in 1:n
178+
tot += x^n # binds symbol `tot` to new value
179+
end
180+
return tot
181+
end
182+
```
183+
However, sometimes such re-binding confuses Zygote, especially if the type of the value changes. Especially if the variable is "boxed", as will happen if you re-bind from within a closure (such as the function created by a `do` block).
184+
185+
## Second derivatives
186+
187+
In principle Zygote supports taking derivatives of derivatives. There are, however, a few problems:
188+
* Quite a few of its rules are not written in a way that is itself differentiable. For instance they may work by making an array then writing into it, which is mutation of the sort forbidden above.
189+
* The complexity of the code grows rapidly, as Zygote differentiates its own un-optimised output.
190+
* Reverse mode over reverse mode is seldom the best algorithm.
191+
192+
The issue tracker has a label for [second order](https://github.com/FluxML/Zygote.jl/issues?q=is%3Aissue+is%3Aopen+label%3A%22second+order%22), which will outline where the bodies are buried.
193+
194+
Often using a different AD system over Zygote is a better solution.
195+
This is what [`hessian`](@ref) does, using ForwardDiff over Zygote, but other combinations are possible.
196+
(Note that rules defined here mean that Zygote over ForwardDiff is translated to ForwardDiff over ForwardDiff.)

0 commit comments

Comments
 (0)