Skip to content

Commit 5990d23

Browse files
committed
add readme v3
1 parent 0d342cb commit 5990d23

1 file changed

Lines changed: 31 additions & 23 deletions

File tree

src/torchjd/scalarization/README.md

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,44 @@ vector of losses) into a single scalar optimizable with a standard `loss.backwar
66
This file is for contributors working on scalarizers. For the list of available scalarizers and their
77
full API, see [torchjd.org](https://torchjd.org/latest/docs/scalarization/).
88

9-
## The contract
9+
## The abstraction
1010

11-
A scalarizer subclasses `Scalarizer` (in [`_scalarizer_base.py`](_scalarizer_base.py)) and implements
12-
one method:
11+
A scalarizer captures a single decision: **how to collapse a vector of objective values into one
12+
scalar to minimize**, using only those values. It is the value-level counterpart of an aggregator,
13+
which makes the same kind of decision at the gradient level. Everything after it (backpropagation,
14+
the optimizer step) is standard PyTorch.
15+
16+
Concretely, it subclasses `Scalarizer` (in [`_scalarizer_base.py`](_scalarizer_base.py)) and
17+
implements one method:
1318

1419
```python
1520
def forward(self, values: Tensor, /) -> Tensor:
1621
...
1722
```
1823

19-
- **Any shape in, scalar out:** it reduces over *all* elements of `values` (0-dim, vector, matrix,
20-
higher-dim) into a 0-dim scalar.
21-
- **`values`, not `losses`:** a scalarizer is generic and not tied to losses.
22-
- **Pure and differentiable:** the output depends only on `values` and the configured parameters, so
23-
that `scalarizer(values).backward()` produces the gradient.
24+
- It reduces over *all* elements of `values`, of any shape, into a 0-dim scalar.
25+
- The result is a **differentiable** function of `values` and the configured parameters, so that
26+
`scalarizer(values).backward()` produces the gradient.
27+
28+
## What is not a scalarizer
29+
30+
A scalarizer sees only the values. Its gradient-level counterpart lives in the
31+
[aggregation](../aggregation) package: an `Aggregator` (which, like a scalarizer, can be stateful)
32+
combines the per-objective *gradients* (the Jacobian or its Gramian) into a single gradient.
33+
34+
So if your method needs the model, its parameters, or the per-objective gradients (gradient norms,
35+
for instance), it is an aggregator, not a scalarizer.
2436

2537
## Adding one
2638

2739
A new scalarizer is a class plus the files that register it. Mirror an existing scalarizer of the
2840
same kind:
2941

30-
- `_<name>.py` the class.
31-
- `__init__.py` the import and an `__all__` entry.
32-
- `docs/source/docs/scalarization/<name>.rst` the docs page, added to the `index.rst` toctree.
33-
- `tests/unit/scalarization/test_<name>.py` the tests.
34-
- `CHANGELOG.md` an entry under `[Unreleased]`.
42+
- `_<name>.py`: the class.
43+
- `__init__.py`: the import and an `__all__` entry.
44+
- `docs/source/docs/scalarization/<name>.rst`: the docs page, added to the `index.rst` toctree.
45+
- `tests/unit/scalarization/test_<name>.py`: the tests.
46+
- `CHANGELOG.md`: an entry under `[Unreleased]`.
3547

3648
## State
3749

@@ -46,19 +58,15 @@ weights, a loss history). When it does:
4658
- **`nn.Parameter` vs buffer:** trainable state is an `nn.Parameter`; non-trained tensors that must
4759
move with `.to()` are registered with `register_buffer`.
4860

49-
## What is not a scalarizer
50-
51-
A scalarizer only ever sees the loss values.
52-
53-
Anything that needs the model, its parameters, or the per-task gradients belongs in the
54-
[aggregation](../aggregation) package as a `Weighting` / `Aggregator`, which operates on the Jacobian
55-
or its Gramian. If you reach for gradient norms or the network inside `forward`, you are writing an
56-
aggregator, not a scalarizer.
61+
Randomness is not state: a scalarizer may draw fresh randomness on each call (like the random
62+
baseline) without being `Stateful`. There is no stochastic mixin; it just uses the global torch RNG,
63+
so document the behavior and let users seed it with `torch.manual_seed`.
5764

5865
## Things to be careful about
5966

60-
- **Determinism and side effects:** the output should depend only on `values` and the configured
61-
parameters. Any state change must be deliberate, explicit, and undone by `reset()`.
67+
- **Determinism and side effects:** the output should depend only on `values`, the configured
68+
parameters, and (if the method is intentionally random) the global RNG. Any state change must be
69+
deliberate, explicit, and undone by `reset()`.
6270
- **Numerical stability:** keep the reduction finite on the edges of its domain (log-sum-exp
6371
centering, an eps under a norm or in a denominator, etc.), and explain any value shift in a comment
6472
and a `.. note::`.

0 commit comments

Comments
 (0)