FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

fix: Validate fp16.loss_scale is finite and non-negative by nathon-lee · Pull Request #7889 · deepspeedai/DeepSpeed · GitHub

fix: Validate fp16.loss_scale is finite and non-negative - #7889

Merged
tohtana merged 12 commits into
deepspeedai:masterfrom
nathon-lee:fix_issue_7852
Mar 13, 2026
Merged

fix: Validate fp16.loss_scale is finite and non-negative#7889
tohtana merged 12 commits into
deepspeedai:masterfrom
nathon-lee:fix_issue_7852

Conversation

nathon-lee commented Mar 6, 2026
edited
Loading

Copy link
Copy Markdown
Contributor

Validate fp16.loss_scale is finite and non-negative

Add a Pydantic field validator to DeepSpeedFP16Config to reject NaN/inf/-inf and negative values for fp16.loss_scale (while keeping 0 as dynamic loss scaling). This prevents invalid configs from silently initializing and causing NaNs during training.

Test:
Run pytest -q tests/unit/runtime/test_precision_config_loss_scale.py

Result:

root@72170d0458e9:/home/DeepSpeed_woo# pytest -q tests/unit/runtime/test_precision_config_loss_scale.py
=================================================================== test session starts ===================================================================
platform linux -- Python 3.11.10, pytest-8.3.5, pluggy-1.6.0 -- /usr/bin/python
cachedir: .pytest_cache
Using --randomly-seed=1526199052
rootdir: /home/DeepSpeed_woo/tests
configfile: pytest.ini
plugins: xdist-3.8.0, randomly-4.0.1, forked-1.6.0, anyio-4.6.0
collected 10 items

tests/unit/runtime/test_precision_config_loss_scale.py::test_fp16_loss_scale_accepts_valid_values[3] PASSED                                         [ 10%]
tests/unit/runtime/test_precision_config_loss_scale.py::test_fp16_loss_scale_accepts_valid_values[0] PASSED                                         [ 20%]
tests/unit/runtime/test_precision_config_loss_scale.py::test_fp16_loss_scale_rejects_invalid_values[inf] PASSED                                     [ 30%]
tests/unit/runtime/test_precision_config_loss_scale.py::test_fp16_loss_scale_accepts_valid_values[1] PASSED                                         [ 40%]
tests/unit/runtime/test_precision_config_loss_scale.py::test_fp16_loss_scale_rejects_invalid_values[nan] PASSED                                     [ 50%]
tests/unit/runtime/test_precision_config_loss_scale.py::test_fp16_loss_scale_accepts_valid_values[2.0] PASSED                                       [ 60%]
tests/unit/runtime/test_precision_config_loss_scale.py::test_fp16_loss_scale_rejects_invalid_values[True] PASSED                                    [ 70%]
tests/unit/runtime/test_precision_config_loss_scale.py::test_fp16_loss_scale_invalid_type_has_clear_error[loss_scale0] PASSED                       [ 80%]
tests/unit/runtime/test_precision_config_loss_scale.py::test_fp16_loss_scale_rejects_invalid_values[-1] PASSED                                      [ 90%]
tests/unit/runtime/test_precision_config_loss_scale.py::test_fp16_loss_scale_invalid_type_has_clear_error[loss_scale1] PASSED                       [100%]

(30 durations < 1s hidden.  Use -vv to show these durations.)
============================================================= 10 passed, 16 warnings in 4.18s =============================================================

Fix issue #7852

chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f0059a795a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread deepspeed/runtime/precision_config.py Outdated
Loss scaling value. Default value of 0 means dynamic loss scaling instead of static loss scale.
"""

@field_validator("loss_scale")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Run loss_scale validator before type coercion

This validator is declared with the default mode="after", so Pydantic will coerce inputs to float first; as a result, the new isinstance(v, bool) guard never triggers because true/false become 1.0/0.0 before _validate_loss_scale runs. In configs that set fp16.loss_scale to a boolean, the value is still silently accepted, which defeats the stated validation goal and can unexpectedly switch to static scaling (true -> 1.0).

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I think this comment makes sense. Can you address it? @nathon-lee

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Thanks — I agree this comment makes sense. I’ll address it and push an update shortly. @tohtana

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Thanks for the review — addressed: the loss_scale validator now runs with mode="before" (so bools are rejected prior to coercion) and I added unit tests for (-1, inf, nan, True).

nathon-lee changed the title Validate fp16.loss_scale is finite and non-negative fix: Validate fp16.loss_scale is finite and non-negative Mar 6, 2026
PKUWZP self-requested a review March 6, 2026 21:17

PKUWZP left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Switch to mode = before and add some tests.

"""

@field_validator("loss_scale")
@classmethod

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality
  • Consider using mode="before" for the entire validator rather than splitting into two validators. A single
    mode="before" validator can handle both the bool check and the finite/negative checks:

    @classmethod
    def _validate_loss_scale(cls, v):
        if isinstance(v, bool):
            raise ValueError("fp16.loss_scale must be a number, not bool")
        v = float(v)
        if not math.isfinite(v):
            raise ValueError("fp16.loss_scale must be a finite number (not inf/-inf/nan)")
        if v < 0:
            raise ValueError("fp16.loss_scale must be >= 0 (0 enables dynamic loss scaling)")
        return v ```
    
    
    
  • Test coverage: There are no tests included. A few unit tests in tests/unit/runtime/ asserting that invalid loss_scale values (-1, float('inf'), float('nan'), True) raise ValidationError would strengthen this PR and prevent regressions.

The existing pattern in the repo uses DeepSpeedFP16Config(loss_scale=...) directly, which makes such tests straightforward.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Thanks — good suggestion. I’ll consolidate into a single mode="before" validator and add unit tests (e.g. -1, inf, nan, True -> ValidationError) using DeepSpeedFP16Config(loss_scale=...). I’ll push an update shortly. @PKUWZP

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Thanks for the review — addressed: the loss_scale validator now runs with mode="before" (so bools are rejected prior to coercion) and I added unit tests for (-1, inf, nan, True).

tohtana Mar 8, 2026
edited
Loading

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

@nathon-lee If we pass an invalid value like [] and {}, won't float() raise TypeError now?
The current master raises Pydantic's ValidationError for these, which is clearer than a raw TypeError.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

@tohtana Thanks for catching this.

I added a try/except (TypeError, ValueError) around float(v) in the mode="before" validator so invalid types (e.g. [], {}) are converted into a clear ValueError, which Pydantic wraps as ValidationError (instead of surfacing a raw TypeError). I also added unit tests covering [] and {} to prevent regressions.

nathon-lee force-pushed the fix_issue_7852 branch 2 times, most recently from f0059a7 to 3ead20d Compare March 7, 2026 03:20
Signed-off-by: nathon-lee <leejianwoo@gmail.com>
Signed-off-by: nathon-lee <leejianwoo@gmail.com>
nathon-lee force-pushed the fix_issue_7852 branch 2 times, most recently from 403cd4c to 39b2b3a Compare March 9, 2026 05:50
Signed-off-by: nathon-lee <leejianwoo@gmail.com>
Signed-off-by: nathon-lee <leejianwoo@gmail.com>

tohtana left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Thank you for the fix! @nathon-lee

tohtana enabled auto-merge (squash) March 13, 2026 00:15

tohtana commented Mar 13, 2026

Copy link
Copy Markdown
Collaborator

@PKUWZP Can you confirm that your request has been met? We need your confirmation to merge this PR.

PKUWZP self-requested a review March 13, 2026 01:11

PKUWZP left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

The changes look good to me.

tohtana merged commit 63eeb11 into deepspeedai:master Mar 13, 2026
1 check passed
nathon-lee added a commit to nathon-lee/DeepSpeed_woo that referenced this pull request Mar 28, 2026
…#7889)

Validate fp16.loss_scale is finite and non-negative

Add a Pydantic field validator to DeepSpeedFP16Config to reject
NaN/inf/-inf and negative values for fp16.loss_scale (while keeping 0 as
dynamic loss scaling). This prevents invalid configs from silently
initializing and causing NaNs during training.

Test:
Run pytest -q tests/unit/runtime/test_precision_config_loss_scale.py

Result:
```
root@72170d0458e9:/home/DeepSpeed_woo# pytest -q tests/unit/runtime/test_precision_config_loss_scale.py
=================================================================== test session starts ===================================================================
platform linux -- Python 3.11.10, pytest-8.3.5, pluggy-1.6.0 -- /usr/bin/python
cachedir: .pytest_cache
Using --randomly-seed=1526199052
rootdir: /home/DeepSpeed_woo/tests
configfile: pytest.ini
plugins: xdist-3.8.0, randomly-4.0.1, forked-1.6.0, anyio-4.6.0
collected 10 items

tests/unit/runtime/test_precision_config_loss_scale.py::test_fp16_loss_scale_accepts_valid_values[3] PASSED                                         [ 10%]
tests/unit/runtime/test_precision_config_loss_scale.py::test_fp16_loss_scale_accepts_valid_values[0] PASSED                                         [ 20%]
tests/unit/runtime/test_precision_config_loss_scale.py::test_fp16_loss_scale_rejects_invalid_values[inf] PASSED                                     [ 30%]
tests/unit/runtime/test_precision_config_loss_scale.py::test_fp16_loss_scale_accepts_valid_values[1] PASSED                                         [ 40%]
tests/unit/runtime/test_precision_config_loss_scale.py::test_fp16_loss_scale_rejects_invalid_values[nan] PASSED                                     [ 50%]
tests/unit/runtime/test_precision_config_loss_scale.py::test_fp16_loss_scale_accepts_valid_values[2.0] PASSED                                       [ 60%]
tests/unit/runtime/test_precision_config_loss_scale.py::test_fp16_loss_scale_rejects_invalid_values[True] PASSED                                    [ 70%]
tests/unit/runtime/test_precision_config_loss_scale.py::test_fp16_loss_scale_invalid_type_has_clear_error[loss_scale0] PASSED                       [ 80%]
tests/unit/runtime/test_precision_config_loss_scale.py::test_fp16_loss_scale_rejects_invalid_values[-1] PASSED                                      [ 90%]
tests/unit/runtime/test_precision_config_loss_scale.py::test_fp16_loss_scale_invalid_type_has_clear_error[loss_scale1] PASSED                       [100%]

(30 durations < 1s hidden.  Use -vv to show these durations.)
============================================================= 10 passed, 16 warnings in 4.18s =============================================================
```
Fix issue deepspeedai#7852

---------

Signed-off-by: nathon-lee <leejianwoo@gmail.com>
Co-authored-by: Masahiro Tanaka <81312776+tohtana@users.noreply.github.com>
Signed-off-by: nathon-lee <leejianwoo@gmail.com>
tohtana added a commit that referenced this pull request Jun 22, 2026
## What

`fp16.loss_scale_window` and `fp16.min_loss_scale` drive dynamic loss
scaling but are not validated, so invalid values initialize silently and
fail later during training:

- **`loss_scale_window`** is used as `stable_interval %
self.scale_window` in `DynamicLossScaler.update_scale`
(`deepspeed/runtime/fp16/loss_scaler.py`), so a value of `0` raises
`ZeroDivisionError` mid-training.
- **`min_loss_scale`** is the loss-scale floor (`max(cur_scale /
scale_factor, min_scale)`); a value `<= 0` collapses dynamic loss
scaling.

This is the same class of silent-misconfiguration bug as
`fp16.loss_scale` accepting `inf`, fixed in #7889.

## Change

Add a single Pydantic `mode="before"` field validator on
`DeepSpeedFP16Config` covering both fields. It rejects `bool`,
non-numeric, non-finite (`inf`/`-inf`/`nan`), and non-positive values,
raising a clear `ValidationError` (e.g. `fp16.loss_scale_window must be
> 0`). Following the #7889 review, `mode="before"` runs prior to type
coercion (so `True` is rejected), and `float()` is wrapped in
`try/except` so `[]`/`{}` surface a clear `ValidationError` rather than
a raw `TypeError`.

## Tests

Adds `tests/unit/runtime/test_precision_config_dynamic_scale.py`,
parametrized over both fields:
- invalid: `0, -1, inf, nan, True, [], {}` -> `ValidationError`
- valid: `1, 1000, "2"` -> accepted

```bash
pytest -q tests/unit/runtime/test_precision_config_dynamic_scale.py
```

The validator logic was verified against the full matrix locally; the
import-level test runs under CI.

---------

Signed-off-by: Aryan <aryansputta@gmail.com>
Co-authored-by: Masahiro Tanaka <81312776+tohtana@users.noreply.github.com>
nathon-lee pushed a commit to nathon-lee/DeepSpeed_woo that referenced this pull request Jul 1, 2026
…ai#8050)

## What

`fp16.loss_scale_window` and `fp16.min_loss_scale` drive dynamic loss
scaling but are not validated, so invalid values initialize silently and
fail later during training:

- **`loss_scale_window`** is used as `stable_interval %
self.scale_window` in `DynamicLossScaler.update_scale`
(`deepspeed/runtime/fp16/loss_scaler.py`), so a value of `0` raises
`ZeroDivisionError` mid-training.
- **`min_loss_scale`** is the loss-scale floor (`max(cur_scale /
scale_factor, min_scale)`); a value `<= 0` collapses dynamic loss
scaling.

This is the same class of silent-misconfiguration bug as
`fp16.loss_scale` accepting `inf`, fixed in deepspeedai#7889.

## Change

Add a single Pydantic `mode="before"` field validator on
`DeepSpeedFP16Config` covering both fields. It rejects `bool`,
non-numeric, non-finite (`inf`/`-inf`/`nan`), and non-positive values,
raising a clear `ValidationError` (e.g. `fp16.loss_scale_window must be
> 0`). Following the deepspeedai#7889 review, `mode="before"` runs prior to type
coercion (so `True` is rejected), and `float()` is wrapped in
`try/except` so `[]`/`{}` surface a clear `ValidationError` rather than
a raw `TypeError`.

## Tests

Adds `tests/unit/runtime/test_precision_config_dynamic_scale.py`,
parametrized over both fields:
- invalid: `0, -1, inf, nan, True, [], {}` -> `ValidationError`
- valid: `1, 1000, "2"` -> accepted

```bash
pytest -q tests/unit/runtime/test_precision_config_dynamic_scale.py
```

The validator logic was verified against the full matrix locally; the
import-level test runs under CI.

---------

Signed-off-by: Aryan <aryansputta@gmail.com>
Co-authored-by: Masahiro Tanaka <81312776+tohtana@users.noreply.github.com>
Signed-off-by: nathon-lee <leejianwoo@gmail.com>
nathon-lee pushed a commit to nathon-lee/DeepSpeed_woo that referenced this pull request Jul 1, 2026
…ai#8050)

## What

`fp16.loss_scale_window` and `fp16.min_loss_scale` drive dynamic loss
scaling but are not validated, so invalid values initialize silently and
fail later during training:

- **`loss_scale_window`** is used as `stable_interval %
self.scale_window` in `DynamicLossScaler.update_scale`
(`deepspeed/runtime/fp16/loss_scaler.py`), so a value of `0` raises
`ZeroDivisionError` mid-training.
- **`min_loss_scale`** is the loss-scale floor (`max(cur_scale /
scale_factor, min_scale)`); a value `<= 0` collapses dynamic loss
scaling.

This is the same class of silent-misconfiguration bug as
`fp16.loss_scale` accepting `inf`, fixed in deepspeedai#7889.

## Change

Add a single Pydantic `mode="before"` field validator on
`DeepSpeedFP16Config` covering both fields. It rejects `bool`,
non-numeric, non-finite (`inf`/`-inf`/`nan`), and non-positive values,
raising a clear `ValidationError` (e.g. `fp16.loss_scale_window must be
> 0`). Following the deepspeedai#7889 review, `mode="before"` runs prior to type
coercion (so `True` is rejected), and `float()` is wrapped in
`try/except` so `[]`/`{}` surface a clear `ValidationError` rather than
a raw `TypeError`.

## Tests

Adds `tests/unit/runtime/test_precision_config_dynamic_scale.py`,
parametrized over both fields:
- invalid: `0, -1, inf, nan, True, [], {}` -> `ValidationError`
- valid: `1, 1000, "2"` -> accepted

```bash
pytest -q tests/unit/runtime/test_precision_config_dynamic_scale.py
```

The validator logic was verified against the full matrix locally; the
import-level test runs under CI.

---------

Signed-off-by: Aryan <aryansputta@gmail.com>
Co-authored-by: Masahiro Tanaka <81312776+tohtana@users.noreply.github.com>
This file contains hidden or 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants


Back | FazBrowse Home | New Git URL