-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
79e9607
commit dc76d3f
Showing
22 changed files
with
459 additions
and
507 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
# Working with state in EvoX | ||
|
||
EvoX is designed around the stateful computation. | ||
|
||
There are two most fundamental classes, namely {class}`Stateful <evox.Stateful>` and {class}`State <evox.State>`. | ||
|
||
All class that involves stateful computation are inherented from `Stateful`. In EvoX, `Algorithm`, `Problem`, `Operator` and workflows are all stateful. | ||
|
||
## The idea behind the design | ||
|
||
```{image} /_static/hierarchical_state.svg | ||
:alt: hierarchical state | ||
:width: 400px | ||
``` | ||
|
||
Here we have five different objects, and notice that they have a hierarchical structure. | ||
To work with such structure, at each level we must "lift the state" by managing the states of child components. | ||
So, the state at the `workflow` level must contains the state of both `algorithm` and `problem`, | ||
and since the state at the `algorithm` level must contains the state of both operators, | ||
the state `workflow` level actual need to handle states from all 5 components. | ||
|
||
However, it is frustrating to managing the hierarchy manually, and it is not good for modular design. | ||
To solve this problem, we introduce `Stateful` and `State`. | ||
|
||
## An overview of Stateful | ||
|
||
In a `Stateful` class, | ||
all immutable data are initialized in `__init__`, | ||
the initial mutable state is generated in `setup`, | ||
besides these two method and private methods(start with "\_"), | ||
all other methods are wrapped with `use_state`. | ||
|
||
```python | ||
class Foo(Stateful): | ||
def __init__(self,): # required | ||
pass | ||
|
||
def setup(self, key) -> State: # optional | ||
pass | ||
|
||
def stateful_func(self, state, args) -> State: # wrapped with use_state | ||
pass | ||
|
||
def _normal_func(self, args) -> vals: # not wrapped | ||
pass | ||
``` | ||
|
||
will be wrapped with `use_state` decorator. This decorator requires the method have the following signature: | ||
|
||
```python | ||
def func(self, state: State, ...) -> Tuple[..., State] | ||
``` | ||
|
||
which is common pattern in stateful computation. | ||
|
||
:::{warning} | ||
Currently, for all user defined private methods, the name of the method should starts with `_`. | ||
::: | ||
|
||
## An overview of State | ||
|
||
In EvoX `State` represents a tree of states, which stores the state of the current object and all child objects. | ||
|
||
## Combined together | ||
|
||
When combined together, | ||
they will automatically go 1 level down in the tree of states, | ||
and merge the subtree back to current level. | ||
|
||
So you could write code like this. | ||
|
||
```python | ||
class FooWorkflow(Stateful): | ||
... | ||
def step(self, state): | ||
population, state = self.algorithm.ask(state) | ||
fitness, state = self.problem.evaluate(state, population) | ||
... | ||
``` | ||
|
||
Notice that, when calling the method `step`, | ||
`state` is the state of the workflow, | ||
but when calling `self.algorithm.ask`, | ||
`state` behaves like the state of the algorithm, | ||
and after the call, the state of the algorithm is automatically merged back into the state of the workflow. |
This file was deleted.
Oops, something went wrong.
38 changes: 14 additions & 24 deletions
38
docs/source/guide/advanced/2-jit-able.rst → docs/source/guide/advanced/2-jit-able.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,47 +1,37 @@ | ||
=================== | ||
Jit-able components | ||
=================== | ||
# Jit-able components | ||
|
||
A common pitfall in jit | ||
======================= | ||
## A common pitfall in jit | ||
|
||
In JAX, it's hard to jump out of a jit-compiled function, meaning if you jit-compile one function, | ||
then all other functions used within this function must also be jit-compiled. | ||
|
||
For example, the follow code will result in compilation error | ||
|
||
.. code-block:: python | ||
```python | ||
@jax.jit | ||
def foo(x): | ||
return bar(x) | ||
|
||
@jax.jit | ||
def foo(x): | ||
return bar(x) | ||
def bar(x): | ||
return x[x > 0] # dynamic index, not jit-able | ||
``` | ||
|
||
def bar(x): | ||
return x[x > 0] # dynamic index, not jit-able | ||
Even though `bar` is not marked with `jax.jit`, it is still compiled as `foo` calls `bar`. | ||
And since bar uses dynamic index, which is not compatible with `jax.jit`, an error will occur. | ||
|
||
Even though ``bar`` is not marked with ``jax.jit``, it is still compiled as ``foo`` calls ``bar``. | ||
And since bar uses dynamic index, which is not compatible with ``jax.jit``, an error will occur. | ||
|
||
Solution | ||
======== | ||
## Solution | ||
|
||
To solve is problem, it is common practice to jit-compile low level components, thus give high level components more freedom. | ||
In EvoX, we have some general rules on whether a function should be jit-able or not. | ||
|
||
+-----------+----------+ | ||
| Component | jit-able | | ||
+===========+==========+ | ||
| --------- | -------- | | ||
| Workflow | Optional | | ||
+-----------+----------+ | ||
| Algorithm | Yes | | ||
+-----------+----------+ | ||
| Problem | Optional | | ||
+-----------+----------+ | ||
| Operators | Yes | | ||
+-----------+----------+ | ||
| Monitor | No | | ||
+-----------+----------+ | ||
|
||
For standard workflow, one can jit compile when not using monitors and working with jit-able problems. | ||
But even though the workflow can be compiled, there isn't much performance gain. | ||
For problems, it depends on the task. | ||
For problems, it depends on the task. |
Oops, something went wrong.