chore: import upstream snapshot with attribution
@@ -0,0 +1,155 @@
|
|||||||
|
---
|
||||||
|
# Refer to the following link for the explanation of each params:
|
||||||
|
# http://releases.llvm.org/8.0.0/tools/clang/docs/ClangFormatStyleOptions.html
|
||||||
|
Language: Cpp
|
||||||
|
# BasedOnStyle: Google
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
AlignEscapedNewlines: Left
|
||||||
|
AlignOperands: true
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowShortBlocksOnASingleLine: true
|
||||||
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
|
AllowShortFunctionsOnASingleLine: All
|
||||||
|
AllowShortIfStatementsOnASingleLine: true
|
||||||
|
AllowShortLoopsOnASingleLine: true
|
||||||
|
# This is deprecated
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: true
|
||||||
|
AlwaysBreakTemplateDeclarations: true
|
||||||
|
BinPackArguments: false
|
||||||
|
BinPackParameters: false
|
||||||
|
BraceWrapping:
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: false
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: false
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
AfterExternBlock: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
IndentBraces: false
|
||||||
|
# disabling the below splits, else, they'll just add to the vertical length of source files!
|
||||||
|
SplitEmptyFunction: false
|
||||||
|
SplitEmptyRecord: false
|
||||||
|
SplitEmptyNamespace: false
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeBraces: WebKit
|
||||||
|
BreakBeforeInheritanceComma: false
|
||||||
|
BreakInheritanceList: BeforeColon
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
|
BreakStringLiterals: true
|
||||||
|
ColumnLimit: 100
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||||
|
# Kept the below 2 to be the same as `IndentWidth` to keep everything uniform
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
FixNamespaceComments: true
|
||||||
|
ForEachMacros:
|
||||||
|
- foreach
|
||||||
|
- Q_FOREACH
|
||||||
|
- BOOST_FOREACH
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '^<ext/.*\.h>'
|
||||||
|
Priority: 2
|
||||||
|
- Regex: '^<.*\.h>'
|
||||||
|
Priority: 1
|
||||||
|
- Regex: '^<.*'
|
||||||
|
Priority: 2
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 3
|
||||||
|
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
||||||
|
IndentCaseLabels: true
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentWidth: 4
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
ObjCBinPackProtocolList: Never
|
||||||
|
ObjCBlockIndentWidth: 4
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PenaltyBreakAssignment: 4
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 1
|
||||||
|
PenaltyBreakComment: 300
|
||||||
|
PenaltyBreakFirstLessLess: 120
|
||||||
|
PenaltyBreakString: 1000
|
||||||
|
PenaltyBreakTemplateDeclaration: 10
|
||||||
|
PenaltyExcessCharacter: 1000000
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 200
|
||||||
|
PointerAlignment: Left
|
||||||
|
RawStringFormats:
|
||||||
|
- Language: Cpp
|
||||||
|
Delimiters:
|
||||||
|
- cc
|
||||||
|
- CC
|
||||||
|
- cpp
|
||||||
|
- Cpp
|
||||||
|
- CPP
|
||||||
|
- 'c++'
|
||||||
|
- 'C++'
|
||||||
|
CanonicalDelimiter: ''
|
||||||
|
- Language: TextProto
|
||||||
|
Delimiters:
|
||||||
|
- pb
|
||||||
|
- PB
|
||||||
|
- proto
|
||||||
|
- PROTO
|
||||||
|
EnclosingFunctions:
|
||||||
|
- EqualsProto
|
||||||
|
- EquivToProto
|
||||||
|
- PARSE_PARTIAL_TEXT_PROTO
|
||||||
|
- PARSE_TEST_PROTO
|
||||||
|
- PARSE_TEXT_PROTO
|
||||||
|
- ParseTextOrDie
|
||||||
|
- ParseTextProtoOrDie
|
||||||
|
CanonicalDelimiter: ''
|
||||||
|
BasedOnStyle: google
|
||||||
|
# Enabling comment reflow causes doxygen comments to be messed up in their formats!
|
||||||
|
ReflowComments: true
|
||||||
|
SortIncludes: true
|
||||||
|
SortUsingDeclarations: true
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterTemplateKeyword: true
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCpp11BracedList: false
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 2
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInContainerLiterals: true
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Cpp11
|
||||||
|
StatementMacros:
|
||||||
|
- Q_UNUSED
|
||||||
|
- QT_REQUIRE_VERSION
|
||||||
|
# Be consistent with indent-width, even for people who use tab for indentation!
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
[flake8]
|
||||||
|
ignore = E,F403,F405,F541,F841,W
|
||||||
|
select = E9,F,W6
|
||||||
|
per-file-ignores =
|
||||||
|
__init__.py:F401
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
name: CI failure report
|
||||||
|
about: Report a DeepSpeed CI failure
|
||||||
|
title: "{{ env.GITHUB_WORKFLOW }} CI test failure"
|
||||||
|
labels: ci-failure
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
The Nightly CI for {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }} failed.
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
name: Bug report (compression)
|
||||||
|
about: Create a DeepSpeed compression related issue to help us improve
|
||||||
|
title: "[BUG]"
|
||||||
|
labels: bug,compression
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**ds_report output**
|
||||||
|
Please run `ds_report` to give us details about your setup.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**System info (please complete the following information):**
|
||||||
|
- OS: [e.g. Ubuntu 18.04]
|
||||||
|
- GPU count and types [e.g. two machines with x8 A100s each]
|
||||||
|
- Interconnects (if applicable) [e.g., two machines connected with 100 Gbps IB]
|
||||||
|
- Python version
|
||||||
|
- Any other relevant info about your setup
|
||||||
|
|
||||||
|
**Launcher context**
|
||||||
|
Are you launching your experiment with the `deepspeed` launcher, MPI, or something else?
|
||||||
|
|
||||||
|
**Docker context**
|
||||||
|
Are you using a specific docker image that you can share?
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
---
|
||||||
|
name: Bug report (DeepSpeed-Chat)
|
||||||
|
about: Create a DeepSpeed-Chat related issue to help us improve
|
||||||
|
title: "[BUG]"
|
||||||
|
labels: bug,deepspeed-chat
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is. Please include which training step you are using and which model you are training.
|
||||||
|
|
||||||
|
**Log output**
|
||||||
|
If you used `train.py` to launch the application, please include the contents of the output log file.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
1. Command/Script to reproduce
|
||||||
|
2. What packages are required and their versions
|
||||||
|
3. How to run the script
|
||||||
|
4. ...
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**ds_report output**
|
||||||
|
Please run `ds_report` to give us details about your setup.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**System info (please complete the following information):**
|
||||||
|
- OS: [e.g. Ubuntu 18.04]
|
||||||
|
- GPU count and types [e.g. two machines with x8 A100s each]
|
||||||
|
- (if applicable) what [DeepSpeed-MII](https://github.com/deepspeedai/deepspeed-mii) version are you using
|
||||||
|
- (if applicable) Hugging Face Transformers/Accelerate/etc. versions
|
||||||
|
- Python version
|
||||||
|
- Any other relevant info about your setup
|
||||||
|
|
||||||
|
**Docker context**
|
||||||
|
Are you using a specific docker image that you can share?
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: "[REQUEST]"
|
||||||
|
labels: enhancement
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
A clear and concise description of what you want to happen.
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context or screenshots about the feature request here.
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
name: Bug report (inference)
|
||||||
|
about: Create a DeepSpeed inference related issue to help us improve
|
||||||
|
title: "[BUG]"
|
||||||
|
labels: bug,inference
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
1. Simple inference script to reproduce
|
||||||
|
2. What packages are required and their versions
|
||||||
|
3. How to run the script
|
||||||
|
4. ...
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**ds_report output**
|
||||||
|
Please run `ds_report` to give us details about your setup.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**System info (please complete the following information):**
|
||||||
|
- OS: [e.g. Ubuntu 18.04]
|
||||||
|
- GPU count and types [e.g. two machines with x8 A100s each]
|
||||||
|
- (if applicable) what [DeepSpeed-MII](https://github.com/deepspeedai/deepspeed-mii) version are you using
|
||||||
|
- (if applicable) Hugging Face Transformers/Accelerate/etc. versions
|
||||||
|
- Python version
|
||||||
|
- Any other relevant info about your setup
|
||||||
|
|
||||||
|
**Docker context**
|
||||||
|
Are you using a specific docker image that you can share?
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
name: Bug report (training)
|
||||||
|
about: Create a DeepSpeed training related issue to help us improve
|
||||||
|
title: "[BUG]"
|
||||||
|
labels: bug,training
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**ds_report output**
|
||||||
|
Please run `ds_report` to give us details about your setup.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**System info (please complete the following information):**
|
||||||
|
- OS: [e.g. Ubuntu 18.04]
|
||||||
|
- GPU count and types [e.g. two machines with x8 A100s each]
|
||||||
|
- Interconnects (if applicable) [e.g., two machines connected with 100 Gbps IB]
|
||||||
|
- Python version
|
||||||
|
- Any other relevant info about your setup
|
||||||
|
|
||||||
|
**Launcher context**
|
||||||
|
Are you launching your experiment with the `deepspeed` launcher, MPI, or something else?
|
||||||
|
|
||||||
|
**Docker context**
|
||||||
|
Are you using a specific docker image that you can share?
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
||||||
@@ -0,0 +1,306 @@
|
|||||||
|
# Diff-based CI test selection
|
||||||
|
|
||||||
|
This document explains the diff-driven test-selection system that lets some GPU CI
|
||||||
|
workflows run only the tests a PR could affect, instead of the whole suite, while
|
||||||
|
still satisfying Required status checks.
|
||||||
|
|
||||||
|
It currently drives **`modal-torch-latest`** (which runs `tests/unit/v1/` on
|
||||||
|
[modal.com](https://modal.com) GPUs), but is built to drive more workflows from
|
||||||
|
one config — see [Adding a workflow](#adding-a-new-workflow).
|
||||||
|
|
||||||
|
- [TL;DR](#tldr)
|
||||||
|
- [Why](#why)
|
||||||
|
- [Moving parts](#moving-parts)
|
||||||
|
- [How a decision is made](#how-a-decision-is-made)
|
||||||
|
- [Driving it (as a contributor)](#driving-it-as-a-contributor)
|
||||||
|
- [Changing it (as a maintainer)](#changing-it-as-a-maintainer)
|
||||||
|
- [Security model](#security-model)
|
||||||
|
- [Failure modes & guarantees](#failure-modes--guarantees)
|
||||||
|
- [FAQ / troubleshooting](#faq--troubleshooting)
|
||||||
|
|
||||||
|
|
||||||
|
## TL;DR
|
||||||
|
|
||||||
|
- On a PR, `ci/tests_fetcher.py` diffs your branch against the base branch, traces
|
||||||
|
the import graph from your changed files to the impacted tests, and writes the
|
||||||
|
list to `ci/.test_selection/test_list.txt`.
|
||||||
|
- The workflow runs pytest on just that list. `push` to `master` and manual runs
|
||||||
|
always run everything.
|
||||||
|
- It is **fail-safe**: anything it can't reason about safely → run the *full* suite.
|
||||||
|
It never silently runs *fewer* tests than reality.
|
||||||
|
- Preview locally:
|
||||||
|
```bash
|
||||||
|
python ci/tests_fetcher.py --base origin/master # what would CI run?
|
||||||
|
python ci/tests_fetcher.py --base origin/master --explain # ...and why?
|
||||||
|
```
|
||||||
|
- Force a full run: put `[test all]` (or `[no filter]`) in a commit message.
|
||||||
|
|
||||||
|
|
||||||
|
## Why
|
||||||
|
|
||||||
|
`modal-torch-latest` is a **Required** check, so it must report a status on every
|
||||||
|
PR — which means we can't use GitHub's path filters (`on.<event>.paths`) to skip
|
||||||
|
it, because a skipped Required job blocks merges. Instead, the job always runs but
|
||||||
|
*selects* what to test: a docs-only PR resolves to "no impacted tests" and exits
|
||||||
|
fast (still green), while a PR touching a leaf module runs only the tests that
|
||||||
|
import it.
|
||||||
|
|
||||||
|
The design is a small, self-contained take on HuggingFace `transformers`'
|
||||||
|
`utils/tests_fetcher.py`.
|
||||||
|
|
||||||
|
|
||||||
|
## Moving parts
|
||||||
|
|
||||||
|
| File | Role |
|
||||||
|
| --- | --- |
|
||||||
|
| `.github/workflows/modal-torch-latest.yml` | The workflow: a `collect-tests` job (runs the fetcher) gating a `deploy` job (runs pytest on modal). |
|
||||||
|
| `ci/tests_fetcher.py` | The selector. AST-parses the repo, builds an import graph, decides `all` / `subset` / `none`, writes the test-list file, emits a job summary. |
|
||||||
|
| `ci/test_tests_fetcher.py` | Self-tests for the selector (pure stdlib; run in `collect-tests`). |
|
||||||
|
| `ci/torch_latest.py` | The modal runner. Reads the test-list file and feeds it to pytest. |
|
||||||
|
| `ci/.test_selection/test_list.txt` | The hand-off artifact (one pytest target per line). Git-ignored. |
|
||||||
|
|
||||||
|
### Job flow
|
||||||
|
|
||||||
|
```
|
||||||
|
pull_request_target / push / workflow_dispatch
|
||||||
|
│
|
||||||
|
┌─────────────┴─────────────┐
|
||||||
|
│ collect-tests │ (no secrets; AST-only)
|
||||||
|
│ checkout PR head │
|
||||||
|
│ restore ci/ from base │
|
||||||
|
│ self-test the fetcher │
|
||||||
|
│ run tests_fetcher.py │
|
||||||
|
│ → mode (all|subset|none) │
|
||||||
|
│ → upload test_list.txt │
|
||||||
|
└─────────────┬──────────────┘
|
||||||
|
│ needs:
|
||||||
|
▼
|
||||||
|
┌────────────────────────────┐
|
||||||
|
│ deploy │ (has modal/HF secrets)
|
||||||
|
│ if mode != none (or manual │
|
||||||
|
│ / collector failed) │
|
||||||
|
│ checkout PR head │
|
||||||
|
│ restore ci/ from base │
|
||||||
|
│ download test_list.txt │
|
||||||
|
│ modal run ci.torch_latest │
|
||||||
|
└────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
`mode` controls `deploy`:
|
||||||
|
|
||||||
|
- **`none`** → `deploy` is skipped. The Required status is still satisfied (a
|
||||||
|
skipped dependent job counts as success here).
|
||||||
|
- **`subset`** → `deploy` runs pytest on exactly the impacted files.
|
||||||
|
- **`all`** → `deploy` runs the whole scope (`tests/unit/v1`).
|
||||||
|
|
||||||
|
|
||||||
|
## How a decision is made
|
||||||
|
|
||||||
|
`TestSelector.select()` in `ci/tests_fetcher.py` runs these checks in order; the
|
||||||
|
first that matches wins:
|
||||||
|
|
||||||
|
1. **No base ref** (push / manual) → `all`.
|
||||||
|
2. **Base ref unresolvable** → `all`.
|
||||||
|
3. **No merge-base** with the base (e.g. shallow clone, unrelated history) → `all`.
|
||||||
|
A diff here would be wrong, so we never narrow on it.
|
||||||
|
4. **Commit message tag** `[test all]` / `[no filter]` anywhere on the branch → `all`.
|
||||||
|
5. **A changed file matches a run-all glob** (`COMMON_RUN_ALL_GLOBS` +
|
||||||
|
the workflow's `extra_run_all_globs`) → `all`. These are files too central or
|
||||||
|
too dynamic to narrow safely: CI scripts, build system, `csrc/`, `op_builder/`,
|
||||||
|
`accelerator/`, shared fixtures (`tests/unit/common.py`, `tests/conftest.py`,
|
||||||
|
`pytest.ini`), and core runtime hubs (`deepspeed/__init__.py`,
|
||||||
|
`deepspeed/runtime/engine.py`, `deepspeed/comm/**`, `deepspeed/accelerator/**`, …).
|
||||||
|
6. **A deleted module is still imported** by a surviving file (a dangling import
|
||||||
|
the graph can't follow) → `all`. A *clean* deletion (importers removed/updated
|
||||||
|
in the same PR) does **not** trigger this.
|
||||||
|
7. Otherwise, **narrow via the import graph** (below). If nothing is impacted →
|
||||||
|
`none`; if everything is → `all`; else → `subset`.
|
||||||
|
|
||||||
|
### The import graph
|
||||||
|
|
||||||
|
- Nodes are Python files under the package roots: `deepspeed/**` and the `unit`
|
||||||
|
test-helper package at `tests/unit/**`.
|
||||||
|
- An edge `A → B` means "B imports A". The selector walks **backwards** from each
|
||||||
|
changed file to every test that (transitively) imports it.
|
||||||
|
- **Opaque hub modules** (`OPAQUE_MODULES`: `deepspeed`, `deepspeed.comm`,
|
||||||
|
`deepspeed.accelerator`): almost every test imports `unit.common`, which imports
|
||||||
|
these. Their `__init__.py` files eagerly pull in huge subtrees, so if treated as
|
||||||
|
normal nodes *any* `deepspeed/**` change would fan out to the whole suite. We
|
||||||
|
therefore don't expand their `__init__` imports; instead, changes to the hubs
|
||||||
|
themselves are caught by the run-all globs in step 5.
|
||||||
|
- **`conftest.py`** changes select every test under that conftest's directory.
|
||||||
|
- **New test files** are selected directly (they have no importers yet).
|
||||||
|
|
||||||
|
### Dynamic edges (`DYNAMIC_EDGES`)
|
||||||
|
|
||||||
|
Some dependencies are wired at runtime (monkey-patching, plugin/registry lookup,
|
||||||
|
JIT-loaded ops, `deepspeed.initialize()`-time `replace_module` injection), so a
|
||||||
|
test can depend on code it never `import`s. `DYNAMIC_EDGES` is a curated map of
|
||||||
|
`changed-file glob → extra test-path globs` that patches these blind spots. It is
|
||||||
|
additive on top of the static graph (and is only consulted if step 5 didn't
|
||||||
|
already short-circuit to `all`).
|
||||||
|
|
||||||
|
|
||||||
|
## Driving it (as a contributor)
|
||||||
|
|
||||||
|
### Preview what CI will run
|
||||||
|
|
||||||
|
The fetcher is pure stdlib — no DeepSpeed/torch install needed, just `git`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Selection for your branch vs. the base branch
|
||||||
|
python ci/tests_fetcher.py --base origin/master
|
||||||
|
cat ci/.test_selection/test_list.txt
|
||||||
|
|
||||||
|
# Explain *why* each test was selected (prints import chains)
|
||||||
|
python ci/tests_fetcher.py --base origin/master --explain
|
||||||
|
```
|
||||||
|
|
||||||
|
`--explain` output looks like:
|
||||||
|
|
||||||
|
```
|
||||||
|
deepspeed/shared.py impacts:
|
||||||
|
tests/unit/v1/test_shared.py <- deepspeed/shared.py
|
||||||
|
tests/unit/v1/moe/test_moe.py <- tests/unit/v1/moe/test_moe.py <- deepspeed/shared.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Escape hatches
|
||||||
|
|
||||||
|
- **Force the full suite for a push:** include `[test all]` (or `[no filter]`)
|
||||||
|
anywhere in a commit message on the branch.
|
||||||
|
- **Touch an infra file:** any change to a run-all glob runs everything.
|
||||||
|
- **Found a missed test?** It's likely a runtime/dynamic dependency the static
|
||||||
|
graph can't see — add a `DYNAMIC_EDGES` entry (see below) and/or report it.
|
||||||
|
|
||||||
|
|
||||||
|
## Changing it (as a maintainer)
|
||||||
|
|
||||||
|
All knobs live in `ci/tests_fetcher.py`. After any change, run the self-tests:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python ci/test_tests_fetcher.py # standalone
|
||||||
|
# or: pytest ci/test_tests_fetcher.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add a run-all trigger
|
||||||
|
|
||||||
|
Add a glob to `TestSelector.COMMON_RUN_ALL_GLOBS` (shared across workflows) or to
|
||||||
|
a specific workflow's `extra_run_all_globs`. Globs match repo-root-relative POSIX
|
||||||
|
paths; `dir/**` matches everything under `dir/`.
|
||||||
|
|
||||||
|
### Add a dynamic edge
|
||||||
|
|
||||||
|
Add to `TestSelector.DYNAMIC_EDGES`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
DYNAMIC_EDGES = {
|
||||||
|
# changed-file glob : test-path globs to pull in when it changes
|
||||||
|
"deepspeed/module_inject/**": ("tests/unit/v1/moe/**",),
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Keep entries conservative: too broad just wastes GPU time; too narrow misses
|
||||||
|
coverage. Prefer fixing it here over widening a run-all glob when only a slice of
|
||||||
|
tests is truly affected.
|
||||||
|
|
||||||
|
### Mark a module opaque
|
||||||
|
|
||||||
|
If a new universal hub starts fanning every change out to the whole suite, add it
|
||||||
|
to `OPAQUE_MODULES` and (usually) add the hub file itself to the run-all globs so
|
||||||
|
real changes to it still run everything.
|
||||||
|
|
||||||
|
### Add a new workflow
|
||||||
|
|
||||||
|
The engine is config-driven (`WORKFLOWS` registry of `WorkflowConfig`). To drive
|
||||||
|
another workflow:
|
||||||
|
|
||||||
|
1. Add an entry:
|
||||||
|
```python
|
||||||
|
WORKFLOWS["my-workflow"] = WorkflowConfig(
|
||||||
|
name="my-workflow",
|
||||||
|
test_scopes=("tests/unit/v2",), # dirs this workflow runs
|
||||||
|
extra_run_all_globs=(".github/workflows/my-workflow.yml",),
|
||||||
|
)
|
||||||
|
```
|
||||||
|
2. In that workflow's YAML, mirror `modal-torch-latest.yml`'s `collect-tests` job
|
||||||
|
and call the fetcher with `--workflow my-workflow`.
|
||||||
|
3. Point the runner at `ci/.test_selection/test_list.txt`.
|
||||||
|
4. Add coverage to `ci/test_tests_fetcher.py` if the scope/behavior differs.
|
||||||
|
|
||||||
|
### Add a self-test
|
||||||
|
|
||||||
|
`ci/test_tests_fetcher.py` builds throwaway git repos (`TmpRepo`) from a synthetic
|
||||||
|
`BASELINE` tree and asserts the resulting `mode`/`tests`. Add a `test_*` function
|
||||||
|
for any new behavior; it runs both standalone and under pytest, and executes in
|
||||||
|
the `collect-tests` CI job, so a broken selector is caught before it mis-picks
|
||||||
|
tests.
|
||||||
|
|
||||||
|
|
||||||
|
## Security model
|
||||||
|
|
||||||
|
The workflow triggers on **`pull_request_target`**, so it runs in the base repo's
|
||||||
|
context and the `deploy` job has the modal/HF **secrets** in scope. To keep PRs
|
||||||
|
from abusing that:
|
||||||
|
|
||||||
|
- `collect-tests` holds **no secrets** and only **AST-parses** (never executes)
|
||||||
|
the PR tree.
|
||||||
|
- **Both jobs restore `ci/` from the base branch** before using it:
|
||||||
|
- `collect-tests` runs the **base** selector + self-tests. This job decides
|
||||||
|
whether the Required `deploy` runs, so it must not trust the PR's own
|
||||||
|
`ci/tests_fetcher.py` — otherwise a PR could rewrite it to emit `mode=none`
|
||||||
|
and skip CI while still going green. The diff is computed from git history, so
|
||||||
|
a PR's `ci/` changes still appear in the diff and (via the base selector's
|
||||||
|
`ci/**` run-all glob) force a full run.
|
||||||
|
- `deploy` runs the **base** orchestration (which drives `modal run` with the
|
||||||
|
secrets), so a PR can't repoint it at the secrets to exfiltrate them.
|
||||||
|
In both jobs the PR's `deepspeed/` + `tests/` are what gets parsed/tested.
|
||||||
|
- The `pull_request_target` trigger types are `review_requested`,
|
||||||
|
`ready_for_review`, and `synchronize`. Because `synchronize` re-runs on every
|
||||||
|
push to an open PR (not just on a maintainer action), the maintainer review is a
|
||||||
|
mitigation, **not** an absolute barrier — the base-`ci/` restore above is the
|
||||||
|
primary protection for the secrets.
|
||||||
|
|
||||||
|
> **Consequence:** changes to `ci/*` (including `tests_fetcher.py` itself) take
|
||||||
|
> effect under `pull_request_target` only after they're **merged**. Validate
|
||||||
|
> `ci/*` changes via a `pull_request`-triggered run or the `modal` CLI locally.
|
||||||
|
>
|
||||||
|
> **Bootstrap:** when the base branch has no selector yet (the PR that introduces
|
||||||
|
> it), the restored base `ci/` won't contain `tests_fetcher.py`; `collect-tests`
|
||||||
|
> detects this and falls back to running the full suite.
|
||||||
|
|
||||||
|
|
||||||
|
## Failure modes & guarantees
|
||||||
|
|
||||||
|
The selector is built to **fail safe — to `all`, never to `none`**:
|
||||||
|
|
||||||
|
- Missing/unresolvable base, no merge-base, a parse error on a file, or **any
|
||||||
|
unexpected exception** in the selector → it falls back to the full suite (the
|
||||||
|
top-level handler in `main()` logs the traceback and sets `mode=all`).
|
||||||
|
- If `collect-tests` fails entirely, `deploy` still runs (and the workflow has an
|
||||||
|
explicit "fail if selection failed" guard) so a broken collector can't let a PR
|
||||||
|
pass without testing.
|
||||||
|
- The only way to run *fewer* tests is a clean, well-understood narrow decision;
|
||||||
|
every uncertain case widens to everything.
|
||||||
|
|
||||||
|
Every run writes a summary to the GitHub job summary (mode, reason, and the
|
||||||
|
selected files) so the decision is auditable from the Actions UI.
|
||||||
|
|
||||||
|
|
||||||
|
## FAQ / troubleshooting
|
||||||
|
|
||||||
|
**My PR shows `mode=none` but I changed code.**
|
||||||
|
Either the change is non-Python / out of the workflow's scope, or your edits
|
||||||
|
aren't committed (the fetcher diffs *committed* history, `merge-base..HEAD`).
|
||||||
|
|
||||||
|
**A relevant test wasn't selected.**
|
||||||
|
Likely a runtime/dynamic dependency. Confirm with `--explain`, then add a
|
||||||
|
`DYNAMIC_EDGES` entry. As a stop-gap, push with `[test all]`.
|
||||||
|
|
||||||
|
**Everything runs even for a tiny change.**
|
||||||
|
You touched a run-all glob (CI/build/shared fixture/core runtime), or a hub module
|
||||||
|
fanned out. Check the job summary's `reason`. If a hub over-fans, consider
|
||||||
|
`OPAQUE_MODULES`.
|
||||||
|
|
||||||
|
**It ran the full suite and the summary says "shallow clone?" / "no merge-base".**
|
||||||
|
The runner didn't have enough history to compute the diff. `collect-tests` uses
|
||||||
|
`fetch-depth: 0`; if you changed that, restore full history for the base.
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
# Test-selection — implementation state / handoff
|
||||||
|
|
||||||
|
Working notes for the diff-based CI test-selection system, so the work can be
|
||||||
|
resumed without re-deriving context. For *how the system works / how to use it*,
|
||||||
|
see [`TEST_SELECTION.md`](TEST_SELECTION.md); this file is only about the **state
|
||||||
|
of the implementation**.
|
||||||
|
|
||||||
|
_Last updated: 2026-06-18._
|
||||||
|
|
||||||
|
|
||||||
|
## Status: complete & locally verified; in review on PR #8077
|
||||||
|
|
||||||
|
The system is implemented end-to-end and passes local checks. Opened as
|
||||||
|
[deepspeedai/DeepSpeed#8077](https://github.com/deepspeedai/DeepSpeed/pull/8077)
|
||||||
|
(scoped to `modal-torch-latest` first; replicate to other workflows if accepted).
|
||||||
|
It has **not** yet run a live `subset`/`deploy` on modal, so the first real runs
|
||||||
|
should be watched.
|
||||||
|
|
||||||
|
### Review fixes applied (Codex bot, PR #8077)
|
||||||
|
|
||||||
|
- **P1 — run the selector from trusted code.** `collect-tests` now restores `ci/`
|
||||||
|
from the base branch before running the selector + self-tests, so a PR can't
|
||||||
|
rewrite `tests_fetcher.py` to emit `mode=none` and skip the Required check. (A
|
||||||
|
PR's `ci/` changes still show in the diff and force a full run via `ci/**`.)
|
||||||
|
Includes a bootstrap fallback: if base has no `tests_fetcher.py` yet, run all.
|
||||||
|
- **P1 — hidden-file artifact.** `actions/upload-artifact@v4` skips dot-prefixed
|
||||||
|
paths by default; `ci/.test_selection/` is one. Added `include-hidden-files:
|
||||||
|
true` so `deploy`'s download doesn't fail.
|
||||||
|
|
||||||
|
> Reminder: under `pull_request_target`, `deploy` restores `ci/` from the base
|
||||||
|
> branch, so changes under `ci/*` (the fetcher included) only take effect once
|
||||||
|
> **merged**. To validate the live behavior before merge, trigger via a
|
||||||
|
> `pull_request`-based run or the `modal` CLI.
|
||||||
|
|
||||||
|
|
||||||
|
## What was built
|
||||||
|
|
||||||
|
A diff-driven selector that, on a PR, runs only the `tests/unit/v1` tests impacted
|
||||||
|
by the changed files, with a fail-safe fallback to the full suite. Driven by the
|
||||||
|
`modal-torch-latest` workflow.
|
||||||
|
|
||||||
|
### Files
|
||||||
|
|
||||||
|
| File | State | Notes |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `ci/tests_fetcher.py` | new/rewritten | Config-driven `TestSelector` class; import-graph selector. |
|
||||||
|
| `ci/test_tests_fetcher.py` | new | 12 stdlib self-tests over synthetic git repos. |
|
||||||
|
| `ci/torch_latest.py` | modified | Reads `DS_TEST_LIST_FILE`, runs pytest on the selected targets (falls back to full `tests/unit/v1`). |
|
||||||
|
| `.github/workflows/modal-torch-latest.yml` | rewritten | `collect-tests` (fetcher) gates `deploy` (modal). |
|
||||||
|
| `.github/workflows/TEST_SELECTION.md` | new | Full design + usage doc. |
|
||||||
|
| `.github/workflows/TEST_SELECTION_STATE.md` | new | This file. |
|
||||||
|
| `CONTRIBUTING.md` | modified | "Diff-based CI test selection" section + link. |
|
||||||
|
| `.gitignore` | modified | Ignores `ci/.test_selection/`. |
|
||||||
|
|
||||||
|
|
||||||
|
## Key design decisions (and why)
|
||||||
|
|
||||||
|
- **Always-runs Required job, selects instead of skips.** `modal-torch-latest` is a
|
||||||
|
Required check, so path filters can't skip it. `collect-tests` decides
|
||||||
|
`all|subset|none`; `none` skips `deploy` while still satisfying the Required
|
||||||
|
status.
|
||||||
|
- **`deploy` tests PR code but restores `ci/` from base.** Selection must reflect
|
||||||
|
PR code, but the orchestration that holds modal/HF secrets must not be
|
||||||
|
PR-controlled. (Security trade-off accepted earlier in the work.)
|
||||||
|
- **Opaque hub modules + curated run-all globs.** `deepspeed`, `deepspeed.comm`,
|
||||||
|
`deepspeed.accelerator` are opaque in the graph to stop universal fan-out; core
|
||||||
|
hubs (`deepspeed/__init__.py`, `runtime/engine.py`, `comm/**`, `accelerator/**`,
|
||||||
|
…) instead live in the run-all globs. (Coarseness fix accepted earlier.)
|
||||||
|
- **Fail-safe to `all`, never `none`.** Every uncertain case (no base, no
|
||||||
|
merge-base, parse error, unexpected exception) widens to the full suite.
|
||||||
|
|
||||||
|
### Improvements implemented in the latest pass (items #3–#11)
|
||||||
|
|
||||||
|
- **#3** Degrade to `all` on any selector error (top-level guard in `main()`).
|
||||||
|
- **#4** `DYNAMIC_EDGES` map for runtime/dynamic deps the AST can't see
|
||||||
|
(seeded: `deepspeed/module_inject/** → tests/unit/v1/moe/**`).
|
||||||
|
- **#5** Deleted `.py` only forces `all` when a *surviving* file still imports it
|
||||||
|
(dangling import); clean deletions no longer over-trigger.
|
||||||
|
- **#6** GitHub job summary (`$GITHUB_STEP_SUMMARY`) with mode/reason/file list;
|
||||||
|
`reason` also on `$GITHUB_OUTPUT`.
|
||||||
|
- **#7** `--explain` prints import chains from changed files to selected tests.
|
||||||
|
- **#8** Escape hatches documented in `CONTRIBUTING.md` + `TEST_SELECTION.md`.
|
||||||
|
- **#9** Self-tests in `ci/test_tests_fetcher.py`, also run in `collect-tests`.
|
||||||
|
- **#10** Robust merge-base: explicit check, `all` if missing; workflow keeps
|
||||||
|
`fetch-depth: 0` with rationale.
|
||||||
|
- **#11** Multi-workflow config: `WORKFLOWS` registry + `WorkflowConfig` +
|
||||||
|
`--workflow` flag.
|
||||||
|
|
||||||
|
|
||||||
|
## Verification done locally
|
||||||
|
|
||||||
|
- `python ci/tests_fetcher.py` self-tests: **12/12 pass**
|
||||||
|
(narrowing, shared importers, core/comm/fixture run-all, commit tag, docs-only →
|
||||||
|
none, new test file, clean vs. dangling delete, dynamic edge, missing base).
|
||||||
|
- Real-repo smoke: `--base`, `--explain`, `--workflow` validation all behave.
|
||||||
|
- Confirmed `$GITHUB_OUTPUT` + `$GITHUB_STEP_SUMMARY` emission and the #3
|
||||||
|
error-fallback path directly.
|
||||||
|
- No linter errors.
|
||||||
|
|
||||||
|
Re-run the core check any time:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python ci/test_tests_fetcher.py
|
||||||
|
python ci/tests_fetcher.py --base origin/master --explain
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Open items / possible follow-ups
|
||||||
|
|
||||||
|
- **Live validation:** watch the first real PR; confirm `collect-tests` artifact
|
||||||
|
hand-off and `deploy` gating behave on Actions + modal.
|
||||||
|
- **`DYNAMIC_EDGES` is minimal.** Only one seeded edge. Expand as blind spots are
|
||||||
|
found (tests that fail on `master`'s full run but weren't selected on their PR
|
||||||
|
are the signal).
|
||||||
|
- **Single workflow wired.** The engine is config-driven (#11) but only
|
||||||
|
`modal-torch-latest` is registered/wired. Other GPU workflows could adopt it by
|
||||||
|
adding a `WorkflowConfig` and mirroring the `collect-tests` job.
|
||||||
|
- **Run-all glob tuning.** The core-hub list is a conservative first cut; revisit
|
||||||
|
if it proves too coarse (full runs on minor edits) or too narrow (missed impact).
|
||||||
|
- **No telemetry.** Consider logging selection stats over time to tune
|
||||||
|
globs/opaque-modules against real false-positive/negative rates.
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
name: amd-mi200
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/amd-mi200.yml'
|
||||||
|
- 'requirements/**'
|
||||||
|
schedule:
|
||||||
|
- cron: "0 0 * * *"
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
amd-tests:
|
||||||
|
name: amd-mi200 / AMD MI200 tests
|
||||||
|
# The type of runner that the job will run on
|
||||||
|
runs-on: [self-hosted, amd, mi200]
|
||||||
|
|
||||||
|
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||||
|
steps:
|
||||||
|
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- id: setup-venv
|
||||||
|
uses: ./.github/workflows/setup-venv
|
||||||
|
|
||||||
|
- name: Install pytorch
|
||||||
|
run: |
|
||||||
|
pip install -U --cache-dir $TORCH_CACHE torch torchvision --index-url https://download.pytorch.org/whl/rocm6.0
|
||||||
|
python -c "import torch; print('torch:', torch.__version__, torch)"
|
||||||
|
python -c "import torch; print('CUDA available:', torch.cuda.is_available())"
|
||||||
|
|
||||||
|
- name: Install transformers
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/huggingface/transformers
|
||||||
|
cd transformers
|
||||||
|
# if needed switch to the last known good SHA until transformers@master is fixed
|
||||||
|
# git checkout 1cc453d33
|
||||||
|
git rev-parse --short HEAD
|
||||||
|
pip install .
|
||||||
|
|
||||||
|
- name: Install (ROCm) apex
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/ROCmSoftwarePlatform/apex.git
|
||||||
|
CURRENT_VER=$(git rev-parse HEAD)
|
||||||
|
INSTALLED_VER=$(cat /blob/amd-apex/.venv_installed_version)
|
||||||
|
if [[ "$CURRENT_VER" != "$INSTALLED_VER" ]]; then
|
||||||
|
pip install -v --disable-pip-version-check --no-cache-dir --no-build-isolation --config-settings="--global-option=--cpp_ext" --config-settings="--global-option=--cuda_ext" --target=/blob/amd-apex/ --upgrade .
|
||||||
|
git rev-parse HEAD > /blob/amd-apex/.venv_installed_version
|
||||||
|
fi
|
||||||
|
echo PYTHONPATH=$PYTHONPATH:/blob/amd-apex/ >> $GITHUB_ENV
|
||||||
|
# Runs a set of commands using the runners shell
|
||||||
|
- name: Install deepspeed
|
||||||
|
run: |
|
||||||
|
pip install .[dev,1bit,autotuning]
|
||||||
|
#python -c "from deepspeed.env_report import cli_main; cli_main()"
|
||||||
|
ds_report
|
||||||
|
|
||||||
|
- name: Python environment
|
||||||
|
run: |
|
||||||
|
pip list
|
||||||
|
|
||||||
|
# Runs a set of commands using the runners shell
|
||||||
|
- name: Unit tests
|
||||||
|
run: |
|
||||||
|
unset TORCH_CUDA_ARCH_LIST # only jit compile for current arch
|
||||||
|
cd tests
|
||||||
|
pytest $PYTEST_OPTS -n 4 --verbose unit/
|
||||||
|
pytest $PYTEST_OPTS -m 'sequential' unit/
|
||||||
|
|
||||||
|
- name: Open GitHub issue if nightly CI fails
|
||||||
|
if: ${{ failure() && (github.event_name == 'schedule') }}
|
||||||
|
uses: JasonEtco/create-an-issue@v2
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
filename: .github/ISSUE_TEMPLATE/ci_failure_report.md
|
||||||
|
update_existing: true
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
################################################################################
|
||||||
|
# DeepSpeed CI - AWS L40S GPU Tests (HuggingFace Accelerate Integration)
|
||||||
|
#
|
||||||
|
# Runs the same tests as modal-accelerate.yml but on AWS self-hosted runners.
|
||||||
|
# Tests DeepSpeed integration with HuggingFace Accelerate library.
|
||||||
|
# Uses 4x NVIDIA L40S GPUs on g6e.12xlarge instances.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
name: aws-accelerate
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-paths:
|
||||||
|
name: aws-accelerate / check paths
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
should_run: ${{ steps.filter.outputs.run_tests }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dorny/paths-filter@v3
|
||||||
|
id: filter
|
||||||
|
with:
|
||||||
|
filters: |
|
||||||
|
run_tests:
|
||||||
|
- '**'
|
||||||
|
- '!docs/**'
|
||||||
|
- '!blogs/**'
|
||||||
|
- '!deepspeed/inference/v2/**'
|
||||||
|
- '!tests/unit/inference/v2/**'
|
||||||
|
|
||||||
|
accelerate-tests:
|
||||||
|
name: aws-accelerate / accelerate integration tests
|
||||||
|
needs: check-paths
|
||||||
|
if: needs.check-paths.outputs.should_run == 'true'
|
||||||
|
runs-on: [self-hosted, gpu-ci, gpu-l40s, l40s-1gpu, aws]
|
||||||
|
timeout-minutes: 60
|
||||||
|
|
||||||
|
container:
|
||||||
|
image: nvidia/cuda:12.6.3-devel-ubuntu22.04
|
||||||
|
options: --gpus all --shm-size "32G"
|
||||||
|
|
||||||
|
env:
|
||||||
|
TORCH_VER: "2.7"
|
||||||
|
CUDA_VER: "12.6"
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Install system dependencies
|
||||||
|
run: |
|
||||||
|
apt-get update && apt-get install -y git git-lfs libaio-dev python3 python3-pip
|
||||||
|
git lfs install
|
||||||
|
ln -sf /usr/bin/python3 /usr/bin/python
|
||||||
|
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
lfs: true
|
||||||
|
|
||||||
|
- name: Install PyTorch
|
||||||
|
run: |
|
||||||
|
pip install torch==2.7.1 torchvision==0.22.1 torchaudio==2.7.1 --index-url https://download.pytorch.org/whl/cu126
|
||||||
|
|
||||||
|
- name: Install Python dependencies
|
||||||
|
run: |
|
||||||
|
pip install --upgrade pip
|
||||||
|
pip install -r requirements/requirements.txt
|
||||||
|
pip install -r requirements/requirements-dev.txt
|
||||||
|
pip install datasets
|
||||||
|
|
||||||
|
- name: Check environment
|
||||||
|
run: |
|
||||||
|
echo "=== GPU Information ==="
|
||||||
|
nvidia-smi
|
||||||
|
echo ""
|
||||||
|
echo "=== CUDA Version ==="
|
||||||
|
nvcc --version
|
||||||
|
echo ""
|
||||||
|
echo "=== Python/PyTorch Info ==="
|
||||||
|
python --version
|
||||||
|
python -c "import torch; print(f'PyTorch: {torch.__version__}')"
|
||||||
|
python -c "import torch; print(f'CUDA available: {torch.cuda.is_available()}')"
|
||||||
|
python -c "import torch; print(f'CUDA devices: {torch.cuda.device_count()}')"
|
||||||
|
python -c "import torch; print(f'BF16 support: {torch.cuda.is_bf16_supported()}')"
|
||||||
|
|
||||||
|
- name: Install DeepSpeed
|
||||||
|
run: |
|
||||||
|
# Initialize CUDA before install so setup.py can detect NCCL version
|
||||||
|
python -c "import torch; torch.cuda.init(); print(f'NCCL version: {torch.cuda.nccl.version()}')"
|
||||||
|
# Use --no-build-isolation so setup.py can access pre-installed PyTorch
|
||||||
|
pip install --no-build-isolation .
|
||||||
|
ds_report
|
||||||
|
# Debug: Check captured torch_info values
|
||||||
|
python -c "from deepspeed.git_version_info import torch_info; print(f'torch_info: {torch_info}')"
|
||||||
|
|
||||||
|
- name: Clone and install Accelerate
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/huggingface/accelerate
|
||||||
|
pip install "./accelerate[testing]"
|
||||||
|
|
||||||
|
- name: Run Accelerate DeepSpeed tests
|
||||||
|
run: |
|
||||||
|
pytest --verbose ./accelerate/tests/deepspeed
|
||||||
@@ -0,0 +1,380 @@
|
|||||||
|
################################################################################
|
||||||
|
# DeepSpeed CI - AWS L40S GPU Full Tests (PyTorch Latest)
|
||||||
|
#
|
||||||
|
# Runs the full DeepSpeed unit test suite on AWS self-hosted runners.
|
||||||
|
# Prefers 4x NVIDIA L40S GPUs on g6e.12xlarge instances, with AWS-side
|
||||||
|
# fallback to 8x A100 nodes when L40S capacity is unavailable.
|
||||||
|
#
|
||||||
|
# This workflow runs:
|
||||||
|
# - Parallel tests with pytest-xdist (-n 8)
|
||||||
|
# - Sequential tests marked with @pytest.mark.sequential
|
||||||
|
# - Nightly schedule: skips if no new commits since last successful run
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
name: aws-torch-latest-full
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 8 * * *' # Daily at 08:00 UTC (midnight PST)
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
torch_preset:
|
||||||
|
description: PyTorch preset to install for manual runs
|
||||||
|
required: false
|
||||||
|
default: '2.10.0-cu126'
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- '2.7.1-cu126'
|
||||||
|
- '2.8.0-cu126'
|
||||||
|
- '2.9.1-cu126'
|
||||||
|
- '2.10.0-cu126'
|
||||||
|
- '2.11.0-cu126'
|
||||||
|
transformers_version:
|
||||||
|
description: Hugging Face Transformers PyPI package version to install
|
||||||
|
required: false
|
||||||
|
default: '4.50.0'
|
||||||
|
type: string
|
||||||
|
transformers_source:
|
||||||
|
description: Hugging Face Transformers source for manual runs
|
||||||
|
required: false
|
||||||
|
default: 'git'
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- 'pypi'
|
||||||
|
- 'git'
|
||||||
|
transformers_ref:
|
||||||
|
description: Hugging Face Transformers git ref to install when source is git
|
||||||
|
required: false
|
||||||
|
default: 'main'
|
||||||
|
type: string
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-changes:
|
||||||
|
name: Check for new commits
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event_name == 'schedule'
|
||||||
|
outputs:
|
||||||
|
has_changes: ${{ steps.check.outputs.has_changes }}
|
||||||
|
steps:
|
||||||
|
- name: Check for commits since last successful run
|
||||||
|
id: check
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
run: |
|
||||||
|
default_branch="${{ github.event.repository.default_branch }}"
|
||||||
|
|
||||||
|
last_sha=$(gh api \
|
||||||
|
"repos/${{ github.repository }}/actions/workflows/aws-torch-latest-full.yml/runs?status=success&event=schedule&branch=${default_branch}&per_page=1" \
|
||||||
|
--jq '.workflow_runs[0].head_sha // empty')
|
||||||
|
|
||||||
|
current_sha="${{ github.sha }}"
|
||||||
|
|
||||||
|
if [ -z "$last_sha" ]; then
|
||||||
|
echo "No previous successful run found - running tests"
|
||||||
|
echo "has_changes=true" >> "$GITHUB_OUTPUT"
|
||||||
|
elif [ "$last_sha" = "$current_sha" ]; then
|
||||||
|
echo "No new commits since last successful run ($last_sha) - skipping"
|
||||||
|
echo "has_changes=false" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "New commits detected: $last_sha -> $current_sha - running tests"
|
||||||
|
echo "has_changes=true" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
unit-tests:
|
||||||
|
name: Unit Tests (Full)
|
||||||
|
needs: [check-changes]
|
||||||
|
if: |
|
||||||
|
!cancelled() &&
|
||||||
|
(github.event_name == 'workflow_dispatch' || needs.check-changes.outputs.has_changes == 'true')
|
||||||
|
runs-on: [self-hosted, gpu-ci, gpu-l40s, l40s-4gpu, aws]
|
||||||
|
timeout-minutes: 180
|
||||||
|
|
||||||
|
container:
|
||||||
|
image: nvidia/cuda:12.6.3-devel-ubuntu22.04
|
||||||
|
# Mount /mnt/aio for async I/O tests (O_DIRECT requires native filesystem, not overlayfs)
|
||||||
|
options: --gpus all --shm-size "32G" -v /mnt/aio:/mnt/aio
|
||||||
|
|
||||||
|
env:
|
||||||
|
DEFAULT_TORCH_PRESET: '2.10.0-cu126'
|
||||||
|
DEFAULT_TRANSFORMERS_SOURCE: 'git'
|
||||||
|
DEFAULT_TRANSFORMERS_VERSION: '4.50.0'
|
||||||
|
DEFAULT_TRANSFORMERS_REF: 'main'
|
||||||
|
CUTLASS_PATH: /opt/cutlass
|
||||||
|
# Disable reuse_dist_env to prevent pool worker cleanup hangs in full test runs
|
||||||
|
DS_DISABLE_REUSE_DIST_ENV: '1'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Install system dependencies
|
||||||
|
run: |
|
||||||
|
apt-get update && apt-get install -y git git-lfs libaio-dev pdsh python3 python3-pip
|
||||||
|
git lfs install
|
||||||
|
ln -sf /usr/bin/python3 /usr/bin/python
|
||||||
|
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
lfs: true
|
||||||
|
|
||||||
|
- name: Resolve dependency inputs
|
||||||
|
env:
|
||||||
|
GITHUB_EVENT_NAME: ${{ github.event_name }}
|
||||||
|
MANUAL_TORCH_PRESET: ${{ github.event.inputs.torch_preset || '' }}
|
||||||
|
MANUAL_TRANSFORMERS_SOURCE: ${{ github.event.inputs.transformers_source || '' }}
|
||||||
|
MANUAL_TRANSFORMERS_VERSION: ${{ github.event.inputs.transformers_version || '' }}
|
||||||
|
MANUAL_TRANSFORMERS_REF: ${{ github.event.inputs.transformers_ref || '' }}
|
||||||
|
run: |
|
||||||
|
if [ "$GITHUB_EVENT_NAME" = 'workflow_dispatch' ] && [ -n "$MANUAL_TORCH_PRESET" ]; then
|
||||||
|
selected_preset="$MANUAL_TORCH_PRESET"
|
||||||
|
else
|
||||||
|
selected_preset="$DEFAULT_TORCH_PRESET"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$GITHUB_EVENT_NAME" = 'workflow_dispatch' ] && [ -n "$MANUAL_TRANSFORMERS_SOURCE" ]; then
|
||||||
|
transformers_source="$MANUAL_TRANSFORMERS_SOURCE"
|
||||||
|
else
|
||||||
|
transformers_source="$DEFAULT_TRANSFORMERS_SOURCE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$GITHUB_EVENT_NAME" = 'workflow_dispatch' ] && [ -n "$MANUAL_TRANSFORMERS_VERSION" ]; then
|
||||||
|
transformers_version="$MANUAL_TRANSFORMERS_VERSION"
|
||||||
|
else
|
||||||
|
transformers_version="$DEFAULT_TRANSFORMERS_VERSION"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$GITHUB_EVENT_NAME" = 'workflow_dispatch' ] && [ -n "$MANUAL_TRANSFORMERS_REF" ]; then
|
||||||
|
transformers_ref="$MANUAL_TRANSFORMERS_REF"
|
||||||
|
else
|
||||||
|
transformers_ref="$DEFAULT_TRANSFORMERS_REF"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$transformers_source" = 'git' ] && [ -z "$transformers_ref" ]; then
|
||||||
|
transformers_ref='main'
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$selected_preset" in
|
||||||
|
'2.7.1-cu126')
|
||||||
|
torch_install_version='2.7.1'
|
||||||
|
torchvision_install_version='0.22.1'
|
||||||
|
torchaudio_install_version='2.7.1'
|
||||||
|
torch_test_version='2.7'
|
||||||
|
cuda_test_version='12.6'
|
||||||
|
pytorch_index_url='https://download.pytorch.org/whl/cu126'
|
||||||
|
;;
|
||||||
|
'2.8.0-cu126')
|
||||||
|
torch_install_version='2.8.0'
|
||||||
|
torchvision_install_version='0.23.0'
|
||||||
|
torchaudio_install_version='2.8.0'
|
||||||
|
torch_test_version='2.8'
|
||||||
|
cuda_test_version='12.6'
|
||||||
|
pytorch_index_url='https://download.pytorch.org/whl/cu126'
|
||||||
|
;;
|
||||||
|
'2.9.1-cu126')
|
||||||
|
torch_install_version='2.9.1'
|
||||||
|
torchvision_install_version='0.24.1'
|
||||||
|
torchaudio_install_version='2.9.1'
|
||||||
|
torch_test_version='2.9'
|
||||||
|
cuda_test_version='12.6'
|
||||||
|
pytorch_index_url='https://download.pytorch.org/whl/cu126'
|
||||||
|
;;
|
||||||
|
'2.10.0-cu126')
|
||||||
|
torch_install_version='2.10.0'
|
||||||
|
torchvision_install_version='0.25.0'
|
||||||
|
torchaudio_install_version='2.10.0'
|
||||||
|
torch_test_version='2.10'
|
||||||
|
cuda_test_version='12.6'
|
||||||
|
pytorch_index_url='https://download.pytorch.org/whl/cu126'
|
||||||
|
;;
|
||||||
|
'2.11.0-cu126')
|
||||||
|
torch_install_version='2.11.0'
|
||||||
|
torchvision_install_version='0.26.0'
|
||||||
|
torchaudio_install_version='2.11.0'
|
||||||
|
torch_test_version='2.11'
|
||||||
|
cuda_test_version='12.6'
|
||||||
|
pytorch_index_url='https://download.pytorch.org/whl/cu126'
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unsupported torch_preset: $selected_preset" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "SELECTED_TORCH_PRESET=$selected_preset"
|
||||||
|
echo "TORCH_INSTALL_VERSION=$torch_install_version"
|
||||||
|
echo "TORCHVISION_INSTALL_VERSION=$torchvision_install_version"
|
||||||
|
echo "TORCHAUDIO_INSTALL_VERSION=$torchaudio_install_version"
|
||||||
|
echo "TORCH_TEST_VERSION=$torch_test_version"
|
||||||
|
echo "CUDA_TEST_VERSION=$cuda_test_version"
|
||||||
|
echo "PYTORCH_INDEX_URL=$pytorch_index_url"
|
||||||
|
echo "TRANSFORMERS_SOURCE=$transformers_source"
|
||||||
|
echo "TRANSFORMERS_VERSION=$transformers_version"
|
||||||
|
echo "TRANSFORMERS_REF=$transformers_ref"
|
||||||
|
} >> "$GITHUB_ENV"
|
||||||
|
|
||||||
|
echo "Selected PyTorch preset: $selected_preset"
|
||||||
|
echo "Resolved install tuple: torch==$torch_install_version torchvision==$torchvision_install_version torchaudio==$torchaudio_install_version"
|
||||||
|
echo "Resolved test expectations: torch=$torch_test_version cuda=$cuda_test_version"
|
||||||
|
echo "Resolved PyTorch index: $pytorch_index_url"
|
||||||
|
echo "Resolved Transformers source: $transformers_source"
|
||||||
|
echo "Resolved Transformers version: $transformers_version"
|
||||||
|
echo "Resolved Transformers ref: $transformers_ref"
|
||||||
|
|
||||||
|
- name: Install CUTLASS
|
||||||
|
run: |
|
||||||
|
git clone --depth 1 --branch v3.5.1 https://github.com/NVIDIA/cutlass.git /opt/cutlass
|
||||||
|
echo "CUTLASS installed at /opt/cutlass"
|
||||||
|
ls -la /opt/cutlass/include/ | head -10
|
||||||
|
|
||||||
|
- name: Install PyTorch
|
||||||
|
run: |
|
||||||
|
pip install \
|
||||||
|
torch=="$TORCH_INSTALL_VERSION" \
|
||||||
|
torchvision=="$TORCHVISION_INSTALL_VERSION" \
|
||||||
|
torchaudio=="$TORCHAUDIO_INSTALL_VERSION" \
|
||||||
|
--index-url "$PYTORCH_INDEX_URL"
|
||||||
|
|
||||||
|
- name: Install Transformers
|
||||||
|
run: |
|
||||||
|
case "$TRANSFORMERS_SOURCE" in
|
||||||
|
'pypi')
|
||||||
|
pip install "transformers==$TRANSFORMERS_VERSION"
|
||||||
|
;;
|
||||||
|
'git')
|
||||||
|
git clone --filter=blob:none https://github.com/huggingface/transformers /tmp/transformers
|
||||||
|
cd /tmp/transformers
|
||||||
|
git checkout "$TRANSFORMERS_REF"
|
||||||
|
resolved_ref="$(git rev-parse HEAD)"
|
||||||
|
echo "TRANSFORMERS_RESOLVED_REF=$resolved_ref" >> "$GITHUB_ENV"
|
||||||
|
echo "Resolved Transformers git ref: $resolved_ref"
|
||||||
|
pip install .
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unsupported TRANSFORMERS_SOURCE: $TRANSFORMERS_SOURCE" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
python -c "import transformers; print('transformers:', transformers.__version__, transformers)"
|
||||||
|
|
||||||
|
- name: Install Python dependencies
|
||||||
|
run: |
|
||||||
|
pip install --upgrade pip
|
||||||
|
pip install -r requirements/requirements.txt
|
||||||
|
pip install -r requirements/requirements-dev.txt
|
||||||
|
pip install -r requirements/requirements-deepcompile.txt
|
||||||
|
pip install pytest-timeout pytest-instafail
|
||||||
|
|
||||||
|
- name: Check environment
|
||||||
|
run: |
|
||||||
|
echo "=== Selected PyTorch Preset ==="
|
||||||
|
echo "Preset: $SELECTED_TORCH_PRESET"
|
||||||
|
echo "Install tuple: torch==$TORCH_INSTALL_VERSION torchvision==$TORCHVISION_INSTALL_VERSION torchaudio==$TORCHAUDIO_INSTALL_VERSION"
|
||||||
|
echo "PyTorch index URL: $PYTORCH_INDEX_URL"
|
||||||
|
echo "Expected test versions: torch=$TORCH_TEST_VERSION cuda=$CUDA_TEST_VERSION"
|
||||||
|
echo "Transformers source: $TRANSFORMERS_SOURCE"
|
||||||
|
echo "Transformers version: $TRANSFORMERS_VERSION"
|
||||||
|
echo "Transformers ref: $TRANSFORMERS_REF"
|
||||||
|
echo "Transformers resolved ref: ${TRANSFORMERS_RESOLVED_REF:-}"
|
||||||
|
echo ""
|
||||||
|
echo "=== GPU Information ==="
|
||||||
|
nvidia-smi
|
||||||
|
echo ""
|
||||||
|
echo "=== CUDA Version ==="
|
||||||
|
nvcc --version
|
||||||
|
echo ""
|
||||||
|
echo "=== Python/PyTorch Info ==="
|
||||||
|
python --version
|
||||||
|
python -c "import torch; print(f'PyTorch: {torch.__version__}')"
|
||||||
|
python -c "import torch; print(f'CUDA available: {torch.cuda.is_available()}')"
|
||||||
|
python -c "import torch; print(f'CUDA devices: {torch.cuda.device_count()}')"
|
||||||
|
python -c "import torch; print(f'BF16 support: {torch.cuda.is_bf16_supported()}')"
|
||||||
|
echo ""
|
||||||
|
echo "=== CUTLASS ==="
|
||||||
|
echo "CUTLASS_PATH: $CUTLASS_PATH"
|
||||||
|
ls -la "$CUTLASS_PATH"/include/ | head -5
|
||||||
|
|
||||||
|
- name: Detect GPU architecture
|
||||||
|
run: |
|
||||||
|
python - <<'PY'
|
||||||
|
import os
|
||||||
|
import torch
|
||||||
|
|
||||||
|
torch.cuda.init()
|
||||||
|
major, minor = torch.cuda.get_device_capability(0)
|
||||||
|
arch = f"{major}.{minor}"
|
||||||
|
gpu_count = torch.cuda.device_count()
|
||||||
|
gpu_name = torch.cuda.get_device_name(0)
|
||||||
|
|
||||||
|
with open(os.environ["GITHUB_ENV"], "a", encoding="utf-8") as env_file:
|
||||||
|
env_file.write(f"TORCH_CUDA_ARCH_LIST={arch}\n")
|
||||||
|
env_file.write(f"GPU_COUNT={gpu_count}\n")
|
||||||
|
|
||||||
|
print(f"Detected GPU: {gpu_name}")
|
||||||
|
print(f"Detected compute capability: {arch}")
|
||||||
|
print(f"Detected GPU count: {gpu_count}")
|
||||||
|
PY
|
||||||
|
|
||||||
|
- name: Install DeepSpeed
|
||||||
|
run: |
|
||||||
|
echo "Using TORCH_CUDA_ARCH_LIST=$TORCH_CUDA_ARCH_LIST"
|
||||||
|
# Initialize CUDA before install so setup.py can detect NCCL version
|
||||||
|
python -c "import torch; torch.cuda.init(); print(f'NCCL version: {torch.cuda.nccl.version()}')"
|
||||||
|
# Use --no-build-isolation so setup.py can access pre-installed PyTorch
|
||||||
|
pip install --no-build-isolation .[dev,1bit,autotuning,deepcompile]
|
||||||
|
ds_report
|
||||||
|
|
||||||
|
- name: Reinstall selected Transformers
|
||||||
|
run: |
|
||||||
|
case "$TRANSFORMERS_SOURCE" in
|
||||||
|
'pypi')
|
||||||
|
pip install --no-deps --force-reinstall "transformers==$TRANSFORMERS_VERSION"
|
||||||
|
;;
|
||||||
|
'git')
|
||||||
|
cd /tmp/transformers
|
||||||
|
pip install --no-deps --force-reinstall .
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unsupported TRANSFORMERS_SOURCE: $TRANSFORMERS_SOURCE" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
python -c "import transformers; print('transformers:', transformers.__version__, transformers)"
|
||||||
|
|
||||||
|
- name: Python environment
|
||||||
|
run: |
|
||||||
|
pip list
|
||||||
|
|
||||||
|
- name: Unit tests (parallel)
|
||||||
|
run: |
|
||||||
|
echo "Running parallel tests with TORCH_CUDA_ARCH_LIST=$TORCH_CUDA_ARCH_LIST on $GPU_COUNT GPUs"
|
||||||
|
cd tests
|
||||||
|
# Skip tests requiring unavailable hardware or known issues:
|
||||||
|
# - nvme checkpointing: no nvme device
|
||||||
|
# - GDS tests: no GPUDirect Storage support
|
||||||
|
# - launcher user_args: pdsh requires SSH server
|
||||||
|
# - zenflow: Stage 3 tests have pre-existing bugs + CUDA/fork issues
|
||||||
|
rm -rf /mnt/aio/pytest
|
||||||
|
pytest --instafail --timeout 600 --forked -n 8 --basetemp=/mnt/aio/pytest unit/ \
|
||||||
|
--ignore=unit/runtime/zero/test_nvme_checkpointing.py \
|
||||||
|
--ignore=unit/ops/aio/test_gds.py \
|
||||||
|
--ignore=unit/launcher/test_user_args.py \
|
||||||
|
--ignore=unit/runtime/zenflow \
|
||||||
|
--ignore=unit/ops/adam/test_zf_torch_adam.py \
|
||||||
|
--torch_ver="$TORCH_TEST_VERSION" --cuda_ver="$CUDA_TEST_VERSION"
|
||||||
|
|
||||||
|
- name: Unit tests (sequential)
|
||||||
|
run: |
|
||||||
|
echo "Running sequential tests with TORCH_CUDA_ARCH_LIST=$TORCH_CUDA_ARCH_LIST on $GPU_COUNT GPUs"
|
||||||
|
cd tests
|
||||||
|
rm -rf /mnt/aio/pytest
|
||||||
|
pytest --instafail --timeout 600 -m 'sequential' --basetemp=/mnt/aio/pytest unit/ \
|
||||||
|
--ignore=unit/runtime/zero/test_nvme_checkpointing.py \
|
||||||
|
--ignore=unit/ops/aio/test_gds.py \
|
||||||
|
--ignore=unit/launcher/test_user_args.py \
|
||||||
|
--ignore=unit/runtime/zenflow \
|
||||||
|
--ignore=unit/ops/adam/test_zf_torch_adam.py \
|
||||||
|
--ignore=unit/ops/deepspeed4science/test_DS4Sci_EvoformerAttention.py \
|
||||||
|
--torch_ver="$TORCH_TEST_VERSION" --cuda_ver="$CUDA_TEST_VERSION"
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
################################################################################
|
||||||
|
# DeepSpeed CI - AWS L40S GPU Tests (PyTorch Latest)
|
||||||
|
#
|
||||||
|
# Runs the same tests as modal-torch-latest.yml but on AWS self-hosted runners.
|
||||||
|
# Uses 4x NVIDIA L40S GPUs on g6e.12xlarge instances.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
name: aws-torch-latest
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-paths:
|
||||||
|
name: aws-torch-latest / check paths
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
should_run: ${{ steps.filter.outputs.run_tests }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dorny/paths-filter@v3
|
||||||
|
id: filter
|
||||||
|
with:
|
||||||
|
filters: |
|
||||||
|
run_tests:
|
||||||
|
- '**'
|
||||||
|
- '!docs/**'
|
||||||
|
- '!blogs/**'
|
||||||
|
- '!deepspeed/inference/v2/**'
|
||||||
|
- '!tests/unit/inference/v2/**'
|
||||||
|
|
||||||
|
unit-tests:
|
||||||
|
name: aws-torch-latest / unit tests (v1)
|
||||||
|
needs: check-paths
|
||||||
|
if: needs.check-paths.outputs.should_run == 'true'
|
||||||
|
runs-on: [self-hosted, gpu-ci, gpu-l40s, l40s-4gpu, aws]
|
||||||
|
timeout-minutes: 60
|
||||||
|
|
||||||
|
container:
|
||||||
|
image: nvidia/cuda:12.6.3-devel-ubuntu22.04
|
||||||
|
options: --gpus all --shm-size "32G"
|
||||||
|
|
||||||
|
env:
|
||||||
|
TORCH_VER: "2.7"
|
||||||
|
CUDA_VER: "12.6"
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Install system dependencies
|
||||||
|
run: |
|
||||||
|
apt-get update && apt-get install -y git git-lfs libaio-dev python3 python3-pip
|
||||||
|
git lfs install
|
||||||
|
ln -sf /usr/bin/python3 /usr/bin/python
|
||||||
|
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
lfs: true
|
||||||
|
|
||||||
|
- name: Install PyTorch
|
||||||
|
run: |
|
||||||
|
pip install torch==2.7.1 torchvision==0.22.1 torchaudio==2.7.1 --index-url https://download.pytorch.org/whl/cu126
|
||||||
|
|
||||||
|
- name: Install Python dependencies
|
||||||
|
run: |
|
||||||
|
pip install --upgrade pip
|
||||||
|
pip install -r requirements/requirements.txt
|
||||||
|
pip install -r requirements/requirements-dev.txt
|
||||||
|
pip install -r requirements/requirements-deepcompile.txt
|
||||||
|
|
||||||
|
- name: Check environment
|
||||||
|
run: |
|
||||||
|
echo "=== GPU Information ==="
|
||||||
|
nvidia-smi
|
||||||
|
echo ""
|
||||||
|
echo "=== CUDA Version ==="
|
||||||
|
nvcc --version
|
||||||
|
echo ""
|
||||||
|
echo "=== Python/PyTorch Info ==="
|
||||||
|
python --version
|
||||||
|
python -c "import torch; print(f'PyTorch: {torch.__version__}')"
|
||||||
|
python -c "import torch; print(f'CUDA available: {torch.cuda.is_available()}')"
|
||||||
|
python -c "import torch; print(f'CUDA devices: {torch.cuda.device_count()}')"
|
||||||
|
python -c "import torch; print(f'BF16 support: {torch.cuda.is_bf16_supported()}')"
|
||||||
|
|
||||||
|
- name: Install DeepSpeed
|
||||||
|
run: |
|
||||||
|
# Initialize CUDA before install so setup.py can detect NCCL version
|
||||||
|
python -c "import torch; torch.cuda.init(); print(f'NCCL version: {torch.cuda.nccl.version()}')"
|
||||||
|
# Use --no-build-isolation so setup.py can access pre-installed PyTorch
|
||||||
|
pip install --no-build-isolation .
|
||||||
|
ds_report
|
||||||
|
# Debug: Check captured torch_info values
|
||||||
|
python -c "from deepspeed.git_version_info import torch_info; print(f'torch_info: {torch_info}')"
|
||||||
|
|
||||||
|
- name: Run unit tests
|
||||||
|
run: |
|
||||||
|
pytest -n 4 --forked --verbose tests/unit/v1/ --torch_ver=${{ env.TORCH_VER }} --cuda_ver=${{ env.CUDA_VER }}
|
||||||
|
|
||||||
|
- name: Run sequential unit tests
|
||||||
|
run: |
|
||||||
|
pytest --verbose -m 'sequential' tests/unit/v1/ --torch_ver=${{ env.TORCH_VER }} --cuda_ver=${{ env.CUDA_VER }}
|
||||||
@@ -0,0 +1,243 @@
|
|||||||
|
name: cpu-torch-latest
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
torch_preset:
|
||||||
|
description: PyTorch CPU preset to install for manual runs
|
||||||
|
required: false
|
||||||
|
default: '2.10.0-cpu'
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- '2.7.1-cpu'
|
||||||
|
- '2.8.0-cpu'
|
||||||
|
- '2.9.1-cpu'
|
||||||
|
- '2.10.0-cpu'
|
||||||
|
transformers_version:
|
||||||
|
description: Hugging Face Transformers PyPI package version to install
|
||||||
|
required: false
|
||||||
|
default: '4.50.0'
|
||||||
|
type: string
|
||||||
|
transformers_source:
|
||||||
|
description: Hugging Face Transformers source for manual runs
|
||||||
|
required: false
|
||||||
|
default: 'git'
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- 'pypi'
|
||||||
|
- 'git'
|
||||||
|
transformers_ref:
|
||||||
|
description: Hugging Face Transformers git ref to install when source is git
|
||||||
|
required: false
|
||||||
|
default: 'main'
|
||||||
|
type: string
|
||||||
|
pull_request:
|
||||||
|
merge_group:
|
||||||
|
branches: [ master ]
|
||||||
|
schedule:
|
||||||
|
- cron: "0 0 * * *"
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-paths:
|
||||||
|
name: cpu-torch-latest / check paths
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: read
|
||||||
|
outputs:
|
||||||
|
should_run: ${{ steps.non_pr.outputs.should_run || steps.filter.outputs.run_tests }}
|
||||||
|
steps:
|
||||||
|
- id: non_pr
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
run: echo "should_run=true" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
|
||||||
|
- uses: dorny/paths-filter@v3
|
||||||
|
id: filter
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
with:
|
||||||
|
predicate-quantifier: every
|
||||||
|
filters: |
|
||||||
|
run_tests:
|
||||||
|
- '**'
|
||||||
|
- '!docs/**'
|
||||||
|
- '!blogs/**'
|
||||||
|
- '!deepspeed/inference/v2/**'
|
||||||
|
- '!tests/unit/inference/v2/**'
|
||||||
|
|
||||||
|
unit-tests:
|
||||||
|
name: cpu-torch-latest / unit tests
|
||||||
|
needs: check-paths
|
||||||
|
if: ${{ !cancelled() && (needs.check-paths.result != 'success' || needs.check-paths.outputs.should_run == 'true') }}
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
|
env:
|
||||||
|
DEFAULT_TORCH_PRESET: '2.10.0-cpu'
|
||||||
|
DEFAULT_TRANSFORMERS_SOURCE: 'git'
|
||||||
|
DEFAULT_TRANSFORMERS_VERSION: '4.50.0'
|
||||||
|
DEFAULT_TRANSFORMERS_REF: 'main'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Fail if path filter failed
|
||||||
|
if: needs.check-paths.result != 'success'
|
||||||
|
run: exit 1
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- id: setup-venv
|
||||||
|
uses: ./.github/workflows/setup-venv
|
||||||
|
|
||||||
|
- name: Install system packages
|
||||||
|
run: |
|
||||||
|
sudo apt-get install -y numactl pdsh
|
||||||
|
|
||||||
|
- name: Resolve dependency inputs
|
||||||
|
env:
|
||||||
|
GITHUB_EVENT_NAME: ${{ github.event_name }}
|
||||||
|
MANUAL_TORCH_PRESET: ${{ github.event.inputs.torch_preset || '' }}
|
||||||
|
MANUAL_TRANSFORMERS_SOURCE: ${{ github.event.inputs.transformers_source || '' }}
|
||||||
|
MANUAL_TRANSFORMERS_VERSION: ${{ github.event.inputs.transformers_version || '' }}
|
||||||
|
MANUAL_TRANSFORMERS_REF: ${{ github.event.inputs.transformers_ref || '' }}
|
||||||
|
run: |
|
||||||
|
if [ "$GITHUB_EVENT_NAME" = 'workflow_dispatch' ] && [ -n "$MANUAL_TORCH_PRESET" ]; then
|
||||||
|
selected_preset="$MANUAL_TORCH_PRESET"
|
||||||
|
else
|
||||||
|
selected_preset="$DEFAULT_TORCH_PRESET"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$GITHUB_EVENT_NAME" = 'workflow_dispatch' ] && [ -n "$MANUAL_TRANSFORMERS_SOURCE" ]; then
|
||||||
|
transformers_source="$MANUAL_TRANSFORMERS_SOURCE"
|
||||||
|
else
|
||||||
|
transformers_source="$DEFAULT_TRANSFORMERS_SOURCE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$GITHUB_EVENT_NAME" = 'workflow_dispatch' ] && [ -n "$MANUAL_TRANSFORMERS_VERSION" ]; then
|
||||||
|
transformers_version="$MANUAL_TRANSFORMERS_VERSION"
|
||||||
|
else
|
||||||
|
transformers_version="$DEFAULT_TRANSFORMERS_VERSION"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$GITHUB_EVENT_NAME" = 'workflow_dispatch' ] && [ -n "$MANUAL_TRANSFORMERS_REF" ]; then
|
||||||
|
transformers_ref="$MANUAL_TRANSFORMERS_REF"
|
||||||
|
else
|
||||||
|
transformers_ref="$DEFAULT_TRANSFORMERS_REF"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$transformers_source" = 'git' ] && [ -z "$transformers_ref" ]; then
|
||||||
|
transformers_ref='main'
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$selected_preset" in
|
||||||
|
'2.7.1-cpu')
|
||||||
|
torch_install_version='2.7.1'
|
||||||
|
torchvision_install_version='0.22.1'
|
||||||
|
torch_test_version='2.7'
|
||||||
|
;;
|
||||||
|
'2.8.0-cpu')
|
||||||
|
torch_install_version='2.8.0'
|
||||||
|
torchvision_install_version='0.23.0'
|
||||||
|
torch_test_version='2.8'
|
||||||
|
;;
|
||||||
|
'2.9.1-cpu')
|
||||||
|
torch_install_version='2.9.1'
|
||||||
|
torchvision_install_version='0.24.1'
|
||||||
|
torch_test_version='2.9'
|
||||||
|
;;
|
||||||
|
'2.10.0-cpu')
|
||||||
|
torch_install_version='2.10.0'
|
||||||
|
torchvision_install_version='0.25.0'
|
||||||
|
torch_test_version='2.10'
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unsupported torch_preset: $selected_preset" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "SELECTED_TORCH_PRESET=$selected_preset"
|
||||||
|
echo "TORCH_INSTALL_VERSION=$torch_install_version"
|
||||||
|
echo "TORCHVISION_INSTALL_VERSION=$torchvision_install_version"
|
||||||
|
echo "TORCH_TEST_VERSION=$torch_test_version"
|
||||||
|
echo "PYTORCH_INDEX_URL=https://download.pytorch.org/whl/cpu"
|
||||||
|
echo "TRANSFORMERS_SOURCE=$transformers_source"
|
||||||
|
echo "TRANSFORMERS_VERSION=$transformers_version"
|
||||||
|
echo "TRANSFORMERS_REF=$transformers_ref"
|
||||||
|
} >> "$GITHUB_ENV"
|
||||||
|
|
||||||
|
echo "Selected PyTorch preset: $selected_preset"
|
||||||
|
echo "Resolved install tuple: torch==$torch_install_version torchvision==$torchvision_install_version"
|
||||||
|
echo "Resolved test expectation: torch=$torch_test_version"
|
||||||
|
echo "Resolved Transformers source: $transformers_source"
|
||||||
|
echo "Resolved Transformers version: $transformers_version"
|
||||||
|
echo "Resolved Transformers ref: $transformers_ref"
|
||||||
|
|
||||||
|
- name: Install PyTorch
|
||||||
|
run: |
|
||||||
|
pip install \
|
||||||
|
torch=="$TORCH_INSTALL_VERSION" \
|
||||||
|
torchvision=="$TORCHVISION_INSTALL_VERSION" \
|
||||||
|
--index-url "$PYTORCH_INDEX_URL"
|
||||||
|
python -c "import torch; print('torch:', torch.__version__, torch)"
|
||||||
|
python -c "import torch; print('CUDA available:', torch.cuda.is_available())"
|
||||||
|
|
||||||
|
- name: Install Transformers
|
||||||
|
run: |
|
||||||
|
case "$TRANSFORMERS_SOURCE" in
|
||||||
|
'pypi')
|
||||||
|
pip install "transformers==$TRANSFORMERS_VERSION"
|
||||||
|
;;
|
||||||
|
'git')
|
||||||
|
git clone --filter=blob:none https://github.com/huggingface/transformers /tmp/transformers
|
||||||
|
cd /tmp/transformers
|
||||||
|
git checkout "$TRANSFORMERS_REF"
|
||||||
|
resolved_ref="$(git rev-parse HEAD)"
|
||||||
|
echo "TRANSFORMERS_RESOLVED_REF=$resolved_ref" >> "$GITHUB_ENV"
|
||||||
|
echo "Resolved Transformers git ref: $resolved_ref"
|
||||||
|
pip install .
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unsupported TRANSFORMERS_SOURCE: $TRANSFORMERS_SOURCE" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
python -c "import transformers; print('transformers:', transformers.__version__, transformers)"
|
||||||
|
|
||||||
|
- name: Install deepspeed
|
||||||
|
run: |
|
||||||
|
pip install .[dev,autotuning]
|
||||||
|
ds_report
|
||||||
|
|
||||||
|
- name: Reinstall selected Transformers
|
||||||
|
run: |
|
||||||
|
case "$TRANSFORMERS_SOURCE" in
|
||||||
|
'pypi')
|
||||||
|
pip install --no-deps --force-reinstall "transformers==$TRANSFORMERS_VERSION"
|
||||||
|
;;
|
||||||
|
'git')
|
||||||
|
cd /tmp/transformers
|
||||||
|
pip install --no-deps --force-reinstall .
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unsupported TRANSFORMERS_SOURCE: $TRANSFORMERS_SOURCE" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
python -c "import transformers; print('transformers:', transformers.__version__, transformers)"
|
||||||
|
|
||||||
|
- name: Python environment
|
||||||
|
run: |
|
||||||
|
pip list
|
||||||
|
|
||||||
|
- name: Unit tests
|
||||||
|
run: |
|
||||||
|
unset TORCH_CUDA_ARCH_LIST # only jit compile for current arch
|
||||||
|
cd tests
|
||||||
|
HF_HOME=/tmp/hf_home/ pytest $PYTEST_OPTS --forked -n 4 unit/ --torch_ver="$TORCH_TEST_VERSION"
|
||||||
|
HF_HOME=/tmp/hf_home/ pytest $PYTEST_OPTS --forked -m 'sequential' unit/ --torch_ver="$TORCH_TEST_VERSION"
|
||||||
@@ -0,0 +1,585 @@
|
|||||||
|
# Copyright (c) DeepSpeed Team.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
# DeepSpeed Team
|
||||||
|
|
||||||
|
name: DCO / required
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
merge_group:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
checks: read
|
||||||
|
contents: read
|
||||||
|
pull-requests: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
dco_required:
|
||||||
|
name: DCO / required
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Validate commit signoffs
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
|
run: |
|
||||||
|
python - <<'PY'
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import urllib.error
|
||||||
|
import urllib.parse
|
||||||
|
import urllib.request
|
||||||
|
|
||||||
|
|
||||||
|
# GitHub App ID for https://github.com/apps/dco.
|
||||||
|
PROBOT_DCO_APP_ID = 1861
|
||||||
|
|
||||||
|
|
||||||
|
def load_event(path):
|
||||||
|
with open(path, encoding="utf-8") as f:
|
||||||
|
return json.load(f)
|
||||||
|
|
||||||
|
|
||||||
|
def fail(message):
|
||||||
|
print(f"::error::{message}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def extract_pr_numbers_from_refs(*refs):
|
||||||
|
numbers = []
|
||||||
|
text = "\n".join(value for value in refs if value)
|
||||||
|
for match in re.finditer(r"(?:^|[/-])pr-(\d+)(?=$|[/-])", text):
|
||||||
|
number = int(match.group(1))
|
||||||
|
if number not in numbers:
|
||||||
|
numbers.append(number)
|
||||||
|
return numbers
|
||||||
|
|
||||||
|
|
||||||
|
def extract_pull_request_number_from_refs(*refs):
|
||||||
|
text = "\n".join(value for value in refs if value)
|
||||||
|
match = re.search(r"(?:^|/)pull/(\d+)(?=/|$)", text)
|
||||||
|
if match:
|
||||||
|
return int(match.group(1))
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def discover_pr_numbers(event_name, event, github_ref):
|
||||||
|
if event_name == "pull_request":
|
||||||
|
number = event.get("number")
|
||||||
|
if number is not None:
|
||||||
|
try:
|
||||||
|
return [int(number)]
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
fail(f"pull_request event had non-integer number: {number!r}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
return [int(event["pull_request"]["number"])]
|
||||||
|
except (KeyError, TypeError, ValueError):
|
||||||
|
ref_number = extract_pull_request_number_from_refs(
|
||||||
|
os.environ.get("GITHUB_REF"),
|
||||||
|
github_ref,
|
||||||
|
event.get("ref"),
|
||||||
|
)
|
||||||
|
if ref_number is not None:
|
||||||
|
return [ref_number]
|
||||||
|
fail("pull_request event did not include a pull request number")
|
||||||
|
|
||||||
|
if event_name == "merge_group":
|
||||||
|
merge_group = event.get("merge_group", {})
|
||||||
|
numbers = extract_pr_numbers_from_refs(
|
||||||
|
merge_group.get("head_ref"),
|
||||||
|
os.environ.get("GITHUB_REF_NAME"),
|
||||||
|
github_ref,
|
||||||
|
event.get("ref"),
|
||||||
|
)
|
||||||
|
if numbers:
|
||||||
|
return numbers
|
||||||
|
|
||||||
|
fail(
|
||||||
|
"merge_group event did not include a parseable PR number. "
|
||||||
|
f"head_ref={merge_group.get('head_ref')!r} "
|
||||||
|
f"GITHUB_REF_NAME={os.environ.get('GITHUB_REF_NAME')!r} "
|
||||||
|
f"GITHUB_REF={github_ref!r}"
|
||||||
|
)
|
||||||
|
|
||||||
|
fail(f"Unsupported event for DCO check: {event_name}")
|
||||||
|
|
||||||
|
|
||||||
|
def graphql_request(query, variables, token):
|
||||||
|
body = json.dumps({"query": query, "variables": variables}).encode("utf-8")
|
||||||
|
req = urllib.request.Request(
|
||||||
|
"https://api.github.com/graphql",
|
||||||
|
data=body,
|
||||||
|
headers={
|
||||||
|
"Accept": "application/vnd.github+json",
|
||||||
|
"Authorization": f"Bearer {token}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-GitHub-Api-Version": "2022-11-28",
|
||||||
|
"User-Agent": "deepspeed-dco-check",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen(req, timeout=30) as response:
|
||||||
|
payload = json.loads(response.read().decode("utf-8"))
|
||||||
|
except urllib.error.HTTPError as exc:
|
||||||
|
detail = exc.read().decode("utf-8", errors="replace")
|
||||||
|
fail(f"GitHub GraphQL request failed: HTTP {exc.code} {detail}")
|
||||||
|
except urllib.error.URLError as exc:
|
||||||
|
fail(f"GitHub GraphQL request failed: {exc}")
|
||||||
|
|
||||||
|
if payload.get("errors"):
|
||||||
|
fail(f"GitHub GraphQL returned errors: {payload['errors']}")
|
||||||
|
return payload["data"]
|
||||||
|
|
||||||
|
|
||||||
|
def rest_request(path, token, fatal=True):
|
||||||
|
url = f"https://api.github.com/repos/{os.environ['GITHUB_REPOSITORY']}{path}"
|
||||||
|
items = []
|
||||||
|
while url:
|
||||||
|
req = urllib.request.Request(
|
||||||
|
url,
|
||||||
|
headers={
|
||||||
|
"Accept": "application/vnd.github+json",
|
||||||
|
"Authorization": f"Bearer {token}",
|
||||||
|
"X-GitHub-Api-Version": "2022-11-28",
|
||||||
|
"User-Agent": "deepspeed-dco-check",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen(req, timeout=30) as response:
|
||||||
|
data = json.loads(response.read().decode("utf-8"))
|
||||||
|
link = response.headers.get("Link", "")
|
||||||
|
except urllib.error.HTTPError as exc:
|
||||||
|
detail = exc.read().decode("utf-8", errors="replace")
|
||||||
|
message = (
|
||||||
|
f"GitHub REST request failed for {path}: "
|
||||||
|
f"HTTP {exc.code} {detail}"
|
||||||
|
)
|
||||||
|
if fatal:
|
||||||
|
fail(message)
|
||||||
|
print(f"::warning::{message}")
|
||||||
|
return None
|
||||||
|
except urllib.error.URLError as exc:
|
||||||
|
message = f"GitHub REST request failed for {path}: {exc}"
|
||||||
|
if fatal:
|
||||||
|
fail(message)
|
||||||
|
print(f"::warning::{message}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
if isinstance(data, list):
|
||||||
|
items.extend(data)
|
||||||
|
else:
|
||||||
|
commits = data.get("commits")
|
||||||
|
if isinstance(commits, list):
|
||||||
|
items.extend(commits)
|
||||||
|
else:
|
||||||
|
return data
|
||||||
|
|
||||||
|
next_url = None
|
||||||
|
for part in link.split(","):
|
||||||
|
if 'rel="next"' in part:
|
||||||
|
next_url = part[part.find("<") + 1:part.find(">")]
|
||||||
|
break
|
||||||
|
url = next_url
|
||||||
|
return items
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_compare_commits(base_sha, head_sha, token):
|
||||||
|
base = urllib.parse.quote(base_sha, safe="")
|
||||||
|
head = urllib.parse.quote(head_sha, safe="")
|
||||||
|
return rest_request(f"/compare/{base}...{head}?per_page=100", token)
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_commit(sha, token):
|
||||||
|
ref = urllib.parse.quote(sha, safe="")
|
||||||
|
return rest_request(f"/commits/{ref}", token, fatal=False)
|
||||||
|
|
||||||
|
|
||||||
|
def has_successful_probot_dco(head_sha, token):
|
||||||
|
if not head_sha:
|
||||||
|
return False
|
||||||
|
|
||||||
|
ref = urllib.parse.quote(head_sha, safe="")
|
||||||
|
payload = rest_request(
|
||||||
|
f"/commits/{ref}/check-runs?check_name=DCO&filter=latest",
|
||||||
|
token,
|
||||||
|
fatal=False,
|
||||||
|
)
|
||||||
|
if not payload:
|
||||||
|
return False
|
||||||
|
|
||||||
|
for check_run in payload.get("check_runs", []):
|
||||||
|
app = check_run.get("app") or {}
|
||||||
|
is_probot_dco = app.get("slug") == "dco" or app.get("id") == PROBOT_DCO_APP_ID
|
||||||
|
if (
|
||||||
|
check_run.get("name") == "DCO"
|
||||||
|
and is_probot_dco
|
||||||
|
and check_run.get("status") == "completed"
|
||||||
|
and check_run.get("conclusion") == "success"
|
||||||
|
):
|
||||||
|
print(
|
||||||
|
"Found successful Probot DCO check for PR head "
|
||||||
|
f"{head_sha}; accepting Probot result."
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_pr_commits(owner, repo, number, token):
|
||||||
|
query = """
|
||||||
|
query($owner: String!, $repo: String!, $number: Int!, $cursor: String) {
|
||||||
|
repository(owner: $owner, name: $repo) {
|
||||||
|
PULL_REQUEST_FIELD(number: $number) {
|
||||||
|
baseRefName
|
||||||
|
baseRepository {
|
||||||
|
nameWithOwner
|
||||||
|
}
|
||||||
|
headRefOid
|
||||||
|
commits(first: 100, after: $cursor) {
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
endCursor
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
commit {
|
||||||
|
oid
|
||||||
|
message
|
||||||
|
author {
|
||||||
|
name
|
||||||
|
email
|
||||||
|
user {
|
||||||
|
login
|
||||||
|
}
|
||||||
|
}
|
||||||
|
committer {
|
||||||
|
name
|
||||||
|
email
|
||||||
|
user {
|
||||||
|
login
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parents(first: 2) {
|
||||||
|
totalCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".replace("PULL_REQUEST_FIELD", "pull" + "Request")
|
||||||
|
cursor = None
|
||||||
|
commits = []
|
||||||
|
base_ref = None
|
||||||
|
base_repo = None
|
||||||
|
head_sha = None
|
||||||
|
|
||||||
|
while True:
|
||||||
|
data = graphql_request(
|
||||||
|
query,
|
||||||
|
{"owner": owner, "repo": repo, "number": number, "cursor": cursor},
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
pull_request = data["repository"]["pull" + "Request"]
|
||||||
|
if pull_request is None:
|
||||||
|
fail(f"PR #{number} was not found")
|
||||||
|
|
||||||
|
base_ref = pull_request["baseRefName"]
|
||||||
|
base_repo = pull_request["baseRepository"]["nameWithOwner"]
|
||||||
|
head_sha = pull_request["headRefOid"]
|
||||||
|
connection = pull_request["commits"]
|
||||||
|
commits.extend(connection["nodes"])
|
||||||
|
|
||||||
|
page_info = connection["pageInfo"]
|
||||||
|
if not page_info["hasNextPage"]:
|
||||||
|
break
|
||||||
|
cursor = page_info["endCursor"]
|
||||||
|
if not cursor:
|
||||||
|
fail(f"PR #{number} pagination did not return an end cursor")
|
||||||
|
|
||||||
|
return {
|
||||||
|
"base_ref": base_ref,
|
||||||
|
"base_repo": base_repo,
|
||||||
|
"head_sha": head_sha,
|
||||||
|
"commits": commits,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def has_signed_off_by(message):
|
||||||
|
return bool(
|
||||||
|
re.search(
|
||||||
|
r"^Signed-off-by:\s+\S.*$",
|
||||||
|
message,
|
||||||
|
flags=re.MULTILINE,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def commit_subject(message):
|
||||||
|
return message.splitlines()[0] if message.splitlines() else "(empty subject)"
|
||||||
|
|
||||||
|
|
||||||
|
def actor_from_graphql(git_actor):
|
||||||
|
git_actor = git_actor or {}
|
||||||
|
user = git_actor.get("user") or {}
|
||||||
|
return {
|
||||||
|
"login": user.get("login") or "",
|
||||||
|
"type": "",
|
||||||
|
"name": git_actor.get("name") or "",
|
||||||
|
"email": git_actor.get("email") or "",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def actor_from_rest(api_actor, git_actor):
|
||||||
|
api_actor = api_actor or {}
|
||||||
|
git_actor = git_actor or {}
|
||||||
|
return {
|
||||||
|
"login": api_actor.get("login") or "",
|
||||||
|
"type": api_actor.get("type") or "",
|
||||||
|
"name": git_actor.get("name") or "",
|
||||||
|
"email": git_actor.get("email") or "",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def is_trusted_bot_actor(actor):
|
||||||
|
actor = actor or {}
|
||||||
|
return str(actor.get("type", "")).lower() == "bot"
|
||||||
|
|
||||||
|
|
||||||
|
def has_bot_marker(actor):
|
||||||
|
actor = actor or {}
|
||||||
|
for key in ("login", "name", "email"):
|
||||||
|
value = str(actor.get(key, "")).lower()
|
||||||
|
if "[bot]" in value:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def actor_label(actor):
|
||||||
|
actor = actor or {}
|
||||||
|
return (
|
||||||
|
actor.get("login")
|
||||||
|
or actor.get("name")
|
||||||
|
or actor.get("email")
|
||||||
|
or "unknown actor"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def is_verified_bot_authored(record, token):
|
||||||
|
author = record.get("author") or {}
|
||||||
|
if is_trusted_bot_actor(author):
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not token or not has_bot_marker(author):
|
||||||
|
return False
|
||||||
|
|
||||||
|
commit = fetch_commit(record["sha"], token)
|
||||||
|
if not commit:
|
||||||
|
return False
|
||||||
|
|
||||||
|
api_author = commit.get("author") or {}
|
||||||
|
if str(api_author.get("type", "")).lower() != "bot":
|
||||||
|
return False
|
||||||
|
|
||||||
|
author["login"] = api_author.get("login") or author.get("login") or ""
|
||||||
|
author["type"] = api_author.get("type") or author.get("type") or ""
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def validate_records(records, seen, token=None, skip_sha=None):
|
||||||
|
failures = []
|
||||||
|
checked = []
|
||||||
|
skipped = []
|
||||||
|
accepted = []
|
||||||
|
for record in records:
|
||||||
|
oid = record["sha"]
|
||||||
|
if oid in seen:
|
||||||
|
continue
|
||||||
|
seen.add(oid)
|
||||||
|
|
||||||
|
if skip_sha and oid == skip_sha:
|
||||||
|
skipped.append(oid)
|
||||||
|
print(f"Skipping merge group head commit {oid}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if record["parent_count"] > 1:
|
||||||
|
skipped.append(oid)
|
||||||
|
print(f"Skipping merge commit {oid}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if is_verified_bot_authored(record, token):
|
||||||
|
skipped.append(oid)
|
||||||
|
print(
|
||||||
|
"Skipping bot-authored commit "
|
||||||
|
f"{oid} ({actor_label(record.get('author'))})"
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
checked.append(oid)
|
||||||
|
message = record.get("message") or ""
|
||||||
|
if not has_signed_off_by(message):
|
||||||
|
failures.append({"sha": oid, "subject": commit_subject(message)})
|
||||||
|
|
||||||
|
return {
|
||||||
|
"checked": checked,
|
||||||
|
"skipped": skipped,
|
||||||
|
"accepted": accepted,
|
||||||
|
"failures": failures,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def validate_pr(owner, repo, number, token, seen):
|
||||||
|
print(f"Validating DCO trailers for PR #{number}")
|
||||||
|
pull_request = fetch_pr_commits(owner, repo, number, token)
|
||||||
|
expected_base = f"{owner}/{repo}"
|
||||||
|
if (
|
||||||
|
pull_request["base_repo"] != expected_base
|
||||||
|
or pull_request["base_ref"] != "master"
|
||||||
|
):
|
||||||
|
fail(
|
||||||
|
f"PR #{number} targets "
|
||||||
|
f"{pull_request['base_repo']}:{pull_request['base_ref']}, "
|
||||||
|
f"expected {expected_base}:master"
|
||||||
|
)
|
||||||
|
|
||||||
|
records = []
|
||||||
|
for node in pull_request["commits"]:
|
||||||
|
commit = node["commit"]
|
||||||
|
records.append(
|
||||||
|
{
|
||||||
|
"sha": commit["oid"],
|
||||||
|
"message": commit.get("message") or "",
|
||||||
|
"author": actor_from_graphql(commit.get("author")),
|
||||||
|
"committer": actor_from_graphql(commit.get("committer")),
|
||||||
|
"parent_count": commit["parents"]["totalCount"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if not records:
|
||||||
|
return {
|
||||||
|
"checked": [],
|
||||||
|
"skipped": [],
|
||||||
|
"accepted": [],
|
||||||
|
"failures": [
|
||||||
|
{
|
||||||
|
"sha": f"PR #{number}",
|
||||||
|
"subject": "no commits returned by pull request commits API",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
if has_successful_probot_dco(pull_request["head_sha"], token):
|
||||||
|
accepted = []
|
||||||
|
for record in records:
|
||||||
|
oid = record["sha"]
|
||||||
|
if oid not in seen:
|
||||||
|
seen.add(oid)
|
||||||
|
accepted.append(oid)
|
||||||
|
return {
|
||||||
|
"checked": [],
|
||||||
|
"skipped": [],
|
||||||
|
"accepted": accepted,
|
||||||
|
"failures": [],
|
||||||
|
}
|
||||||
|
|
||||||
|
return validate_records(records, seen, token=token)
|
||||||
|
|
||||||
|
|
||||||
|
def verify_merge_group_range_coverage(event, token, seen):
|
||||||
|
merge_group = event.get("merge_group", {})
|
||||||
|
base_sha = merge_group.get("base_sha")
|
||||||
|
head_sha = merge_group.get("head_sha") or os.environ.get("GITHUB_SHA")
|
||||||
|
if not base_sha or not head_sha:
|
||||||
|
fail(
|
||||||
|
"merge_group event did not include base_sha and head_sha. "
|
||||||
|
f"base_sha={base_sha!r} head_sha={head_sha!r} "
|
||||||
|
f"GITHUB_SHA={os.environ.get('GITHUB_SHA')!r}"
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"Checking merge group range coverage {base_sha}...{head_sha}")
|
||||||
|
commits = fetch_compare_commits(base_sha, head_sha, token)
|
||||||
|
records = []
|
||||||
|
for commit in commits:
|
||||||
|
git_commit = commit.get("commit", {}) or {}
|
||||||
|
records.append(
|
||||||
|
{
|
||||||
|
"sha": commit.get("sha", ""),
|
||||||
|
"message": git_commit.get("message", "") or "",
|
||||||
|
"author": actor_from_rest(
|
||||||
|
commit.get("author"),
|
||||||
|
git_commit.get("author"),
|
||||||
|
),
|
||||||
|
"committer": actor_from_rest(
|
||||||
|
commit.get("committer"),
|
||||||
|
git_commit.get("committer"),
|
||||||
|
),
|
||||||
|
"parent_count": len(commit.get("parents", [])),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if not commits:
|
||||||
|
fail(f"merge_group compare range {base_sha}...{head_sha} returned no commits")
|
||||||
|
|
||||||
|
return validate_records(records, seen, token=token, skip_sha=head_sha)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
repository = os.environ["GITHUB_REPOSITORY"]
|
||||||
|
owner, repo = repository.split("/", 1)
|
||||||
|
event_name = os.environ["GITHUB_EVENT_NAME"]
|
||||||
|
github_ref = os.environ.get("GITHUB_REF")
|
||||||
|
token = os.environ["GITHUB_TOKEN"]
|
||||||
|
event = load_event(os.environ["GITHUB_EVENT_PATH"])
|
||||||
|
|
||||||
|
pull_numbers = discover_pr_numbers(event_name, event, github_ref)
|
||||||
|
failures = []
|
||||||
|
checked = set()
|
||||||
|
skipped = set()
|
||||||
|
accepted = set()
|
||||||
|
seen = set()
|
||||||
|
|
||||||
|
for number in sorted(pull_numbers):
|
||||||
|
result = validate_pr(owner, repo, number, token, seen)
|
||||||
|
failures.extend(result["failures"])
|
||||||
|
checked.update(result["checked"])
|
||||||
|
skipped.update(result["skipped"])
|
||||||
|
accepted.update(result.get("accepted", []))
|
||||||
|
|
||||||
|
if event_name == "merge_group":
|
||||||
|
result = verify_merge_group_range_coverage(
|
||||||
|
event,
|
||||||
|
token,
|
||||||
|
seen,
|
||||||
|
)
|
||||||
|
failures.extend(result["failures"])
|
||||||
|
checked.update(result["checked"])
|
||||||
|
skipped.update(result["skipped"])
|
||||||
|
accepted.update(result.get("accepted", []))
|
||||||
|
|
||||||
|
if failures:
|
||||||
|
for failure in failures:
|
||||||
|
print(f"::error::{failure['sha']}: {failure['subject']}")
|
||||||
|
fail(
|
||||||
|
f"{len(failures)} commit(s) are missing a Signed-off-by trailer."
|
||||||
|
)
|
||||||
|
|
||||||
|
print(
|
||||||
|
"DCO validation passed for "
|
||||||
|
f"{len(pull_numbers)} pull request(s): "
|
||||||
|
f"checked {len(checked)} commit(s), "
|
||||||
|
f"accepted {len(accepted)} commit(s) via Probot DCO, "
|
||||||
|
f"skipped {len(skipped)} merge, bot, or synthetic commit(s)."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
PY
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
name: Formatting
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
'**'
|
||||||
|
merge_group:
|
||||||
|
branches: [ master ]
|
||||||
|
schedule:
|
||||||
|
- cron: "0 0 * * *"
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
# formatting and basic install on cpu-only machine
|
||||||
|
unit-tests:
|
||||||
|
name: formatting / formatting checks
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: environment
|
||||||
|
run: |
|
||||||
|
which python
|
||||||
|
python --version
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
# Previously we would do pip install .[dev] but this is causing out of
|
||||||
|
# space errors start with torch 2.1.0 release
|
||||||
|
grep -E "clang-format|pre-commit" requirements/requirements-dev.txt | xargs pip install
|
||||||
|
|
||||||
|
- name: Formatting checks
|
||||||
|
run: |
|
||||||
|
pip show pre-commit clang-format
|
||||||
|
pre-commit run --all-files
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
name: hpu-gaudi2-nightly
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 0 * * *"
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/hpu-gaudi2-nightly.yml"
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
unit-tests:
|
||||||
|
name: hpu-gaudi2-nightly / unit tests
|
||||||
|
# The type of runner that the job will run on
|
||||||
|
runs-on: [self-hosted, intel, gaudi2]
|
||||||
|
container:
|
||||||
|
image: vault.habana.ai/gaudi-docker/1.21.0/ubuntu22.04/habanalabs/pytorch-installer-2.6.0:latest
|
||||||
|
ports:
|
||||||
|
- 80
|
||||||
|
options: --runtime=habana -e HABANA_VISIBLE_DEVICES=all -e OMPI_MCA_btl_vader_single_copy_mechanism=none --cap-add=sys_nice
|
||||||
|
|
||||||
|
env:
|
||||||
|
PT_HPU_LAZY_MODE: 0
|
||||||
|
TORCHINDUCTOR_COMPILE_THREADS: 1
|
||||||
|
TEST_LIST: |
|
||||||
|
test_adamw.py
|
||||||
|
test_bf16.py
|
||||||
|
test_ds_config_dict.py
|
||||||
|
test_dynamic_loss_scale.py
|
||||||
|
test_latest_checkpoint.py
|
||||||
|
test_moe_checkpoint.py
|
||||||
|
test_multi_output_model.py
|
||||||
|
test_other_optimizer.py
|
||||||
|
test_pipe.py
|
||||||
|
test_pipeline.py
|
||||||
|
test_universal_checkpoint.py
|
||||||
|
test_zero_context_return.py
|
||||||
|
test_zero_leaf_module.py
|
||||||
|
test_zero_offloadpp.py
|
||||||
|
test_zero_tiled.py
|
||||||
|
test_autotp_training.py
|
||||||
|
test_ulysses.py
|
||||||
|
|
||||||
|
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||||
|
steps:
|
||||||
|
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Check container state
|
||||||
|
run: |
|
||||||
|
ldd --version
|
||||||
|
hl-smi -L
|
||||||
|
python -c "import torch; print('torch:', torch.__version__, torch)"
|
||||||
|
python -c "import torch; print('CUDA available:', torch.cuda.is_available())"
|
||||||
|
|
||||||
|
- name: Install transformers
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/huggingface/transformers
|
||||||
|
cd transformers
|
||||||
|
git rev-parse --short HEAD
|
||||||
|
pip install .
|
||||||
|
|
||||||
|
- name: Install deepspeed
|
||||||
|
run: |
|
||||||
|
pip install .[dev,autotuning]
|
||||||
|
ds_report
|
||||||
|
|
||||||
|
- name: Python environment
|
||||||
|
run: |
|
||||||
|
pip list
|
||||||
|
|
||||||
|
- name: Unit tests
|
||||||
|
run: |
|
||||||
|
unset TORCH_CUDA_ARCH_LIST # only jit compile for current arch
|
||||||
|
cd tests
|
||||||
|
export PT_HPU_LAZY_MODE=${PT_HPU_LAZY_MODE}
|
||||||
|
export TORCHINDUCTOR_COMPILE_THREADS=${TORCHINDUCTOR_COMPILE_THREADS}
|
||||||
|
TEST_LIST=$(echo "$TEST_LIST" | awk 'NF{printf "%s%s", (NR>1 ? " or " : ""), $0} END{if (NR>1) print ""}')
|
||||||
|
echo "TEST_LIST ${TEST_LIST}"
|
||||||
|
pytest --verbose unit/ -k "${TEST_LIST}"
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
name: hpu-gaudi2
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 0 * * *"
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/hpu-gaudi2.yml"
|
||||||
|
- "accelerator/hpu_accelerator.py"
|
||||||
|
- "op_builder/hpu/**"
|
||||||
|
- "deepspeed/runtime/engine.py"
|
||||||
|
- "deepspeed/runtime/bf16_optimizer.py"
|
||||||
|
- "deepspeed/runtime/zero/stage_1_and_2.py"
|
||||||
|
- "deepspeed/runtime/zero/stage3.py"
|
||||||
|
- "deepspeed/runtime/zero/partition_parameters.py"
|
||||||
|
- "deepspeed/runtime/zero/partitioned_param_coordinator.py"
|
||||||
|
- "deepspeed/runtime/zero/parameter_offload.py"
|
||||||
|
- "deepspeed/runtime/pipe/engine.py"
|
||||||
|
- "deepspeed/runtime/utils.py"
|
||||||
|
- "deepspeed/inference/engine.py"
|
||||||
|
- "deepspeed/module_inject/auto_tp.py"
|
||||||
|
- "deepspeed/module_inject/replace_module.py"
|
||||||
|
- "deepspeed/module_inject/load_checkpoint.py"
|
||||||
|
- "deepspeed/module_inject/inject.py"
|
||||||
|
- "deepspeed/ops/transformer/**"
|
||||||
|
- "deepspeed/ops/adam/**"
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
unit-tests:
|
||||||
|
name: hpu-gaudi2 / unit tests
|
||||||
|
# The type of runner that the job will run on
|
||||||
|
runs-on: [self-hosted, intel, gaudi2]
|
||||||
|
container:
|
||||||
|
image: vault.habana.ai/gaudi-docker/1.21.0/ubuntu22.04/habanalabs/pytorch-installer-2.6.0:latest
|
||||||
|
ports:
|
||||||
|
- 80
|
||||||
|
options: --runtime=habana -e HABANA_VISIBLE_DEVICES=all -e OMPI_MCA_btl_vader_single_copy_mechanism=none --cap-add=sys_nice
|
||||||
|
|
||||||
|
env:
|
||||||
|
PT_HPU_LAZY_MODE: 0
|
||||||
|
TORCHINDUCTOR_COMPILE_THREADS: 1
|
||||||
|
TEST_LIST: |
|
||||||
|
test_accelerator.py
|
||||||
|
test_autotuning.py
|
||||||
|
test_compression.py
|
||||||
|
test_dist.py
|
||||||
|
test_elastic.py
|
||||||
|
test_ds_arguments.py
|
||||||
|
test_run.py
|
||||||
|
test_multinode_runner.py
|
||||||
|
test_moe_tp.py
|
||||||
|
test_monitor.py
|
||||||
|
(test_zero_optimizer.py and (TestSaveTensorClone or TestZeRONonDistributed))
|
||||||
|
(test_latest_checkpoint.py and test_missing_latest)
|
||||||
|
test_reshape_checkpoint.py
|
||||||
|
test_shared_weights.py
|
||||||
|
test_sparse.py
|
||||||
|
test_tag_validation.py
|
||||||
|
test_pipe_module.py
|
||||||
|
(test_flops_profiler.py and test_flops_profiler_in_inference)
|
||||||
|
test_get_optim_files.py
|
||||||
|
test_groups.py
|
||||||
|
test_partition_balanced.py
|
||||||
|
(test_adamw.py and TestAdamConfigs)
|
||||||
|
test_coalesced_collectives.py
|
||||||
|
test_activation_checkpointing_non_reentrant.py
|
||||||
|
test_activation_checkpointing.py
|
||||||
|
test_data.py
|
||||||
|
(test_ds_config_dict.py and (TestBasicConfig or TestBatchConfig))
|
||||||
|
test_ds_config_model.py
|
||||||
|
test_mup_optimizers.py
|
||||||
|
(test_pld.py and test_pld_schedule)
|
||||||
|
test_runtime_utils.py
|
||||||
|
test_pipe_schedule.py
|
||||||
|
test_topology.py
|
||||||
|
(test_ds_initialize.py and (TestClientOptimizer or TestClientLrScheduler))
|
||||||
|
test_csr.py
|
||||||
|
(test_fp16.py and (TestZeroEmptyGrad or TestZeroAllowUntestedOptimizer))
|
||||||
|
(test_bf16.py and TestZeroDtypeCocktail)
|
||||||
|
test_partition.py
|
||||||
|
test_ignore_unused_parameters.py
|
||||||
|
test_zero_config.py
|
||||||
|
test_zero_context_ancestry.py
|
||||||
|
(test_zero_context.py and not TestSerialContext)
|
||||||
|
test_zero_dynamic_class.py
|
||||||
|
test_zero_nesting_init.py
|
||||||
|
test_zeropp.py
|
||||||
|
(test_zero.py and (TestZero3ParamPartitioningLargeParam or TestZero3ParamPartitioningLargeParam))
|
||||||
|
(test_linear.py and (TestLoRALinear or TestBasicLinear))
|
||||||
|
(test_ctx.py and TestEngine)
|
||||||
|
|
||||||
|
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||||
|
steps:
|
||||||
|
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Check container state
|
||||||
|
run: |
|
||||||
|
ldd --version
|
||||||
|
hl-smi -L
|
||||||
|
python -c "import torch; print('torch:', torch.__version__, torch)"
|
||||||
|
python -c "import torch; print('CUDA available:', torch.cuda.is_available())"
|
||||||
|
|
||||||
|
- name: Install transformers
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/huggingface/transformers
|
||||||
|
cd transformers
|
||||||
|
# if needed switch to the last known good SHA until transformers@master is fixed
|
||||||
|
# git checkout 981c276
|
||||||
|
git rev-parse --short HEAD
|
||||||
|
pip install .
|
||||||
|
|
||||||
|
- name: Install deepspeed
|
||||||
|
run: |
|
||||||
|
pip install .[dev,autotuning]
|
||||||
|
ds_report
|
||||||
|
|
||||||
|
- name: Python environment
|
||||||
|
run: |
|
||||||
|
pip list
|
||||||
|
|
||||||
|
- name: Unit tests
|
||||||
|
run: |
|
||||||
|
unset TORCH_CUDA_ARCH_LIST # only jit compile for current arch
|
||||||
|
cd tests
|
||||||
|
export PT_HPU_LAZY_MODE=${PT_HPU_LAZY_MODE}
|
||||||
|
export TORCHINDUCTOR_COMPILE_THREADS=${TORCHINDUCTOR_COMPILE_THREADS}
|
||||||
|
TEST_LIST=$(echo "$TEST_LIST" | awk 'NF{printf "%s%s", (NR>1 ? " or " : ""), $0} END{if (NR>1) print ""}')
|
||||||
|
echo "TEST_LIST ${TEST_LIST}"
|
||||||
|
pytest --verbose unit/ -k "${TEST_LIST}"
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
name: modal-accelerate
|
||||||
|
|
||||||
|
# This CI is running on modal.com's GPUs.
|
||||||
|
#
|
||||||
|
# It's set up here on github actions and then the cloned repo is sent to modal and everything
|
||||||
|
# happens on their hw - see ci/accelerate.py for where the actual vm is loaded, updated and the tests are
|
||||||
|
# run.
|
||||||
|
#
|
||||||
|
# Both files are annotated to what's important and how one might change or update things if needed.
|
||||||
|
#
|
||||||
|
# Note that since this is a Required job we can't use `on.push.path` file filter - we are using
|
||||||
|
# collect-tests job to do the filtering for us so that the job can be skipped and satisfy the
|
||||||
|
# Required status for PRs to pass.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
# you have to switch to `pull_request` if you need to change the CI job's python script,
|
||||||
|
# otherwise GH will use a master version of the CI files, ignoring the modifications in the PR -
|
||||||
|
# the other way is to use modal cli to test this job from one's host - it'd require setting up
|
||||||
|
# modal secrets
|
||||||
|
# pull_request:
|
||||||
|
pull_request_target:
|
||||||
|
paths-ignore:
|
||||||
|
- 'docs/**'
|
||||||
|
- 'blogs/**'
|
||||||
|
- 'deepspeed/inference/v2/**'
|
||||||
|
- 'tests/unit/inference/v2/**'
|
||||||
|
types: [review_requested, ready_for_review, synchronize]
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
collect-tests:
|
||||||
|
name: modal-accelerate / collect tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: read
|
||||||
|
outputs:
|
||||||
|
deepspeed: ${{ steps.filter.outputs.deepspeed }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
lfs: true
|
||||||
|
|
||||||
|
- name: Filter changed files
|
||||||
|
uses: dorny/paths-filter@v2
|
||||||
|
id: filter
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
filters: |
|
||||||
|
deepspeed:
|
||||||
|
- 'deepspeed/**'
|
||||||
|
- '.github/workflows/modal*.yml'
|
||||||
|
- 'ci/**'
|
||||||
|
- 'tests/unit/**'
|
||||||
|
- 'csrc/**'
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
name: modal-accelerate / DeepSpeedAI CI
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: collect-tests
|
||||||
|
env:
|
||||||
|
# these are created at https://modal.com/settings/deepspeedai/tokens
|
||||||
|
# they are then added to the repo's secrets at https://github.com/deepspeedai/deepspeed/settings/secrets/actions
|
||||||
|
MODAL_TOKEN_ID: ${{ secrets.MODAL_TOKEN_ID }}
|
||||||
|
MODAL_TOKEN_SECRET: ${{ secrets.MODAL_TOKEN_SECRET }}
|
||||||
|
# this one comes from https://huggingface.co/settings/profile of the bot user
|
||||||
|
# and it too is then updated at https://github.com/deepspeedai/deepspeed/settings/secrets/actions
|
||||||
|
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
||||||
|
|
||||||
|
if: needs.collect-tests.outputs.deepspeed == 'true'
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
lfs: true
|
||||||
|
|
||||||
|
- name: Install Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: "3.10"
|
||||||
|
cache: 'pip' # caching pip dependencies
|
||||||
|
|
||||||
|
- name: Install build dependencies
|
||||||
|
run: |
|
||||||
|
pip install uv # much faster than pip
|
||||||
|
uv pip install --system modal
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: |
|
||||||
|
modal run -m ci.accelerate
|
||||||
@@ -0,0 +1,241 @@
|
|||||||
|
name: modal-torch-latest
|
||||||
|
|
||||||
|
# This CI is running on modal.com's GPUs.
|
||||||
|
#
|
||||||
|
# It's set up here on github actions and then the cloned repo is sent to modal and everything
|
||||||
|
# happens on their hw - see ci/torch_latest.py for where the actual vm is loaded, updated and the tests are
|
||||||
|
# run.
|
||||||
|
#
|
||||||
|
# Both files are annotated to what's important and how one might change or update things if needed.
|
||||||
|
#
|
||||||
|
# Note that since this is a Required job we can't use `on.push.path` file filter - we are using
|
||||||
|
# the collect-tests job to do the filtering for us so that the job can be skipped and satisfy the
|
||||||
|
# Required status for PRs to pass.
|
||||||
|
#
|
||||||
|
# Test selection: collect-tests runs ci/tests_fetcher.py, which traces the import
|
||||||
|
# graph from the PR's changed files to the impacted tests/unit/v1 tests. It emits a
|
||||||
|
# `mode` (all | subset | none) and a test-list file:
|
||||||
|
# - none -> deploy is skipped (Required status is still satisfied by the skip)
|
||||||
|
# - subset -> deploy runs pytest on only the impacted test files
|
||||||
|
# - all -> deploy runs the whole tests/unit/v1 suite
|
||||||
|
#
|
||||||
|
# Full design / how to drive & change it: .github/workflows/TEST_SELECTION.md
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
torch_preset:
|
||||||
|
description: Modal PyTorch/CUDA image preset for manual runs
|
||||||
|
required: false
|
||||||
|
default: '2.10.0-cuda12.8'
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- '2.7.1-cuda12.8'
|
||||||
|
- '2.8.0-cuda12.8'
|
||||||
|
- '2.9.1-cuda12.8'
|
||||||
|
- '2.10.0-cuda12.8'
|
||||||
|
- '2.11.0-cuda12.8'
|
||||||
|
transformers_source:
|
||||||
|
description: Hugging Face Transformers source for manual runs
|
||||||
|
required: false
|
||||||
|
default: 'git'
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- 'requirements'
|
||||||
|
- 'git'
|
||||||
|
transformers_ref:
|
||||||
|
description: Hugging Face Transformers git ref to install when source is git
|
||||||
|
required: false
|
||||||
|
default: 'main'
|
||||||
|
type: string
|
||||||
|
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
pull_request_target:
|
||||||
|
types: [review_requested, ready_for_review, synchronize]
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
collect-tests:
|
||||||
|
name: modal-torch-latest / collect tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: read
|
||||||
|
outputs:
|
||||||
|
mode: ${{ steps.fetch.outputs.mode }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
# For PRs, check out the PR head so the fetcher sees the proposed
|
||||||
|
# deepspeed/ + tests/ code. This job holds NO secrets. The selection
|
||||||
|
# *logic* (ci/) is restored from the base branch in a later step so a PR
|
||||||
|
# can't tamper with the decision (see "Use base-branch CI scripts").
|
||||||
|
# Falls back to the pushed/manual commit for non-PR events.
|
||||||
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
# Full history so the merge-base with the base branch is always present.
|
||||||
|
# This is the robust (if slower) choice: a shallow clone that can't reach
|
||||||
|
# the fork point would produce a wrong diff. The fetcher additionally
|
||||||
|
# guards against a missing merge-base by falling back to the full suite,
|
||||||
|
# so we never run a narrow (false-negative) selection on a bad base.
|
||||||
|
fetch-depth: 0
|
||||||
|
lfs: true
|
||||||
|
|
||||||
|
- name: Determine base ref
|
||||||
|
id: base
|
||||||
|
env:
|
||||||
|
EVENT_NAME: ${{ github.event_name }}
|
||||||
|
BASE_REF: ${{ github.base_ref }}
|
||||||
|
run: |
|
||||||
|
git config --global --add safe.directory '*'
|
||||||
|
if [ "$EVENT_NAME" = "pull_request_target" ]; then
|
||||||
|
# Fetch the base branch's full history too, so a merge-base always exists.
|
||||||
|
git fetch --no-tags origin "$BASE_REF"
|
||||||
|
echo "ref=origin/$BASE_REF" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
# push to master / manual dispatch -> no diff base -> run the full suite
|
||||||
|
echo "ref=" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Use base-branch CI scripts
|
||||||
|
# SECURITY: this job decides whether the Required `deploy` job runs. Under
|
||||||
|
# pull_request_target we must NOT trust the PR's own ci/ for that decision:
|
||||||
|
# a PR could rewrite ci/tests_fetcher.py to emit `mode=none` (or its self
|
||||||
|
# tests) and skip CI entirely while still satisfying the Required check.
|
||||||
|
# So run the selector + self-tests from the *base* branch's ci/. The diff is
|
||||||
|
# computed from git history, so a PR's ci/ changes still show up in the diff
|
||||||
|
# and (via the base selector's `ci/**` run-all glob) force a full run.
|
||||||
|
if: github.event_name == 'pull_request_target'
|
||||||
|
env:
|
||||||
|
BASE_REF: ${{ github.base_ref }}
|
||||||
|
run: |
|
||||||
|
git config --global --add safe.directory '*'
|
||||||
|
git checkout "origin/$BASE_REF" -- ci/
|
||||||
|
|
||||||
|
- name: Self-test the fetcher
|
||||||
|
# Pure-stdlib self-tests for the selector (only needs git + python). Runs
|
||||||
|
# here so a broken selector is caught before it (mis)picks tests. Skipped
|
||||||
|
# when the base branch has no selector yet (bootstrap; see below).
|
||||||
|
run: |
|
||||||
|
if [ -f ci/test_tests_fetcher.py ]; then
|
||||||
|
python3 ci/test_tests_fetcher.py
|
||||||
|
else
|
||||||
|
echo "No base-branch ci/test_tests_fetcher.py (bootstrap) -> skipping self-tests."
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Select impacted tests
|
||||||
|
id: fetch
|
||||||
|
# Pure-stdlib script; the runner's system python is fine (no deps needed).
|
||||||
|
# If the base branch doesn't have the selector yet (e.g. the PR that
|
||||||
|
# introduces it), the restored base ci/ won't contain tests_fetcher.py, so
|
||||||
|
# fall back to the full suite -- safe, and unblocks the bootstrap PR.
|
||||||
|
run: |
|
||||||
|
if [ -f ci/tests_fetcher.py ]; then
|
||||||
|
python3 ci/tests_fetcher.py --workflow modal-torch-latest --base "${{ steps.base.outputs.ref }}"
|
||||||
|
else
|
||||||
|
echo "No base-branch ci/tests_fetcher.py (bootstrap) -> running the full suite."
|
||||||
|
echo "mode=all" >> "$GITHUB_OUTPUT"
|
||||||
|
mkdir -p ci/.test_selection
|
||||||
|
printf 'tests/unit/v1\n' > ci/.test_selection/test_list.txt
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Upload test selection
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: modal-torch-latest-test-selection
|
||||||
|
path: ci/.test_selection/test_list.txt
|
||||||
|
# The path lives under a dot-folder; upload-artifact treats dot-prefixed
|
||||||
|
# paths as hidden and skips them by default (only warns), which would make
|
||||||
|
# deploy's download fail. Opt in explicitly.
|
||||||
|
include-hidden-files: true
|
||||||
|
retention-days: 3
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
name: modal-torch-latest / DeepSpeedAI CI
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: collect-tests
|
||||||
|
|
||||||
|
# Run when: manual dispatch, OR the selector failed (fail closed so the Required
|
||||||
|
# check doesn't silently pass), OR the diff impacts at least one test (mode != none).
|
||||||
|
# (!cancelled() adopted from upstream so a cancelled run doesn't trigger deploy.)
|
||||||
|
if: ${{ !cancelled() && (github.event_name == 'workflow_dispatch' || needs.collect-tests.result != 'success' || needs.collect-tests.outputs.mode != 'none') }}
|
||||||
|
steps:
|
||||||
|
- name: Fail if test selection failed
|
||||||
|
if: github.event_name != 'workflow_dispatch' && needs.collect-tests.result != 'success'
|
||||||
|
run: exit 1
|
||||||
|
|
||||||
|
- name: Checkout Repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
# Test the PR's code (not the base) so diff-driven selection is meaningful.
|
||||||
|
# SECURITY NOTE: under pull_request_target this runs PR-authored code while
|
||||||
|
# the modal/HF secrets are on this runner. The trigger types include
|
||||||
|
# `synchronize`, so this re-runs on every push to an open PR (not only on a
|
||||||
|
# maintainer's review_requested / ready_for_review action) -- do not treat
|
||||||
|
# the maintainer gate as an absolute barrier. The primary protection is that
|
||||||
|
# the CI orchestration (which actually receives the secrets) is restored
|
||||||
|
# from the base branch in the next step, so a PR can't repoint it at the
|
||||||
|
# secrets; only the PR's deepspeed/ + tests/ run, inside modal.
|
||||||
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
lfs: true
|
||||||
|
|
||||||
|
- name: Use base-branch CI scripts
|
||||||
|
# Run the *base* version of ci/ (which drives `modal run` with the secrets in
|
||||||
|
# scope) rather than the PR's, so a PR can't modify the orchestration to
|
||||||
|
# exfiltrate secrets. The PR's deepspeed/ + tests/ are still what gets tested.
|
||||||
|
# (As noted in the header, changes to ci/* must be validated via `pull_request`
|
||||||
|
# or the modal CLI, since pull_request_target always uses the base ci/ here.)
|
||||||
|
if: github.event_name == 'pull_request_target'
|
||||||
|
env:
|
||||||
|
BASE_REF: ${{ github.base_ref }}
|
||||||
|
run: |
|
||||||
|
git config --global --add safe.directory '*'
|
||||||
|
git fetch --no-tags --depth=1 origin "$BASE_REF"
|
||||||
|
git checkout "origin/$BASE_REF" -- ci/
|
||||||
|
|
||||||
|
- name: Install Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: "3.10"
|
||||||
|
cache: 'pip' # caching pip dependencies
|
||||||
|
|
||||||
|
- name: Download test selection
|
||||||
|
if: needs.collect-tests.result == 'success'
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: modal-torch-latest-test-selection
|
||||||
|
path: ci/.test_selection
|
||||||
|
|
||||||
|
- name: Install build dependencies
|
||||||
|
run: |
|
||||||
|
pip install uv # much faster than pip
|
||||||
|
uv pip install --system modal
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
env:
|
||||||
|
MODAL_TORCH_PRESET: ${{ github.event.inputs.torch_preset || '2.10.0-cuda12.8' }}
|
||||||
|
MODAL_TRANSFORMERS_SOURCE: ${{ github.event.inputs.transformers_source || 'git' }}
|
||||||
|
MODAL_TRANSFORMERS_REF: ${{ github.event.inputs.transformers_ref || 'main' }}
|
||||||
|
# Diff-selected pytest targets produced by collect-tests (falls back to the
|
||||||
|
# full tests/unit/v1 suite if the file is missing/empty).
|
||||||
|
DS_TEST_LIST_FILE: ci/.test_selection/test_list.txt
|
||||||
|
# these are created at https://modal.com/settings/deepspeedai/tokens
|
||||||
|
# they are then added to the repo's secrets at https://github.com/deepspeedai/deepspeed/settings/secrets/actions
|
||||||
|
MODAL_TOKEN_ID: ${{ secrets.MODAL_TOKEN_ID }}
|
||||||
|
MODAL_TOKEN_SECRET: ${{ secrets.MODAL_TOKEN_SECRET }}
|
||||||
|
# this one comes from https://huggingface.co/settings/profile of the bot user
|
||||||
|
# and it too is then updated at https://github.com/deepspeedai/deepspeed/settings/secrets/actions
|
||||||
|
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
||||||
|
run: |
|
||||||
|
modal run -m ci.torch_latest
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
name: no-torch
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- 'accelerator/**'
|
||||||
|
- '.github/workflows/no-torch.yml'
|
||||||
|
- 'op_builder/**'
|
||||||
|
schedule:
|
||||||
|
- cron: "0 0 * * *"
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
unit-tests:
|
||||||
|
name: no-torch / source distribution build
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- id: setup-venv
|
||||||
|
uses: ./.github/workflows/setup-venv
|
||||||
|
|
||||||
|
- name: Python environment
|
||||||
|
run: |
|
||||||
|
pip uninstall torch --yes
|
||||||
|
pip install setuptools
|
||||||
|
pip install build
|
||||||
|
pip list
|
||||||
|
|
||||||
|
- name: Build deepspeed
|
||||||
|
run: |
|
||||||
|
DS_BUILD_STRING=" " python -m build --sdist
|
||||||
|
|
||||||
|
- name: Open GitHub issue if nightly CI fails
|
||||||
|
if: ${{ failure() && (github.event_name == 'schedule') }}
|
||||||
|
uses: JasonEtco/create-an-issue@v2
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
filename: .github/ISSUE_TEMPLATE/ci_failure_report.md
|
||||||
|
update_existing: true
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
name: nv-a6000
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- 'accelerator/cuda_accelerator.py'
|
||||||
|
- 'deepspeed/inference/v2/**'
|
||||||
|
- 'tests/unit/inference/v2/**'
|
||||||
|
- '.github/workflows/nv-a6000.yml'
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
mii_branch:
|
||||||
|
description: 'DeepSpeed-MII Branch'
|
||||||
|
required: false
|
||||||
|
default: 'main'
|
||||||
|
type: string
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
unit-tests:
|
||||||
|
name: nv-a6000 / inference and MII tests
|
||||||
|
runs-on: [self-hosted, nvidia, a6000]
|
||||||
|
container:
|
||||||
|
image: nvcr.io/nvidia/pytorch:25.01-py3
|
||||||
|
ports:
|
||||||
|
- 80
|
||||||
|
options: --gpus all --shm-size "8G"
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Check container state
|
||||||
|
run: |
|
||||||
|
ldd --version
|
||||||
|
nvcc --version
|
||||||
|
nvidia-smi
|
||||||
|
python -c "import torch; print('torch:', torch.__version__, torch)"
|
||||||
|
python -c "import torch; print('CUDA available:', torch.cuda.is_available())"
|
||||||
|
- name: Install transformers
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/huggingface/transformers
|
||||||
|
cd transformers
|
||||||
|
# if you need to use an older transformers version temporarily in case of breakage
|
||||||
|
# git checkout 981c276
|
||||||
|
git rev-parse --short HEAD
|
||||||
|
python -m pip install .
|
||||||
|
- name: Install deepspeed
|
||||||
|
run: |
|
||||||
|
python -m pip install docutils==0.18.1 jinja2==3.0 urllib3==1.26.11 ninja
|
||||||
|
python -m pip install .[dev,1bit,autotuning,inf]
|
||||||
|
ds_report
|
||||||
|
- name: Python environment
|
||||||
|
run: |
|
||||||
|
python -m pip list
|
||||||
|
- name: Unit tests
|
||||||
|
run: |
|
||||||
|
unset TORCH_CUDA_ARCH_LIST # only jit compile for current arch
|
||||||
|
cd tests
|
||||||
|
python -m pytest --color=yes --durations=0 --verbose -rF -m 'inference_v2' unit/ --torch_ver="2.6" --cuda_ver="12"
|
||||||
|
python -m pytest --color=yes --durations=0 --verbose -rF -m 'inference_v2_ops' unit/ --torch_ver="2.6" --cuda_ver="12"
|
||||||
|
- name: MII unit tests
|
||||||
|
run: |
|
||||||
|
BRANCH="main"
|
||||||
|
if [[ ! -z "${{ github.event.inputs.mii_branch }}" ]]; then
|
||||||
|
BRANCH="${{ github.event.inputs.mii_branch }}"
|
||||||
|
fi
|
||||||
|
echo "Cloning DeepSpeed-MII branch: $BRANCH"
|
||||||
|
git clone -b $BRANCH --depth=1 https://github.com/deepspeedai/DeepSpeed-MII.git
|
||||||
|
cd DeepSpeed-MII
|
||||||
|
pip install .[dev]
|
||||||
|
cd tests
|
||||||
|
python -m pytest --color=yes --durations=0 --verbose -rF ./
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
name: nv-accelerate-v100
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
unit-tests:
|
||||||
|
runs-on: [self-hosted, nvidia, cu124, v100]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- id: setup-venv
|
||||||
|
uses: ./.github/workflows/setup-venv
|
||||||
|
|
||||||
|
- name: Install pytorch
|
||||||
|
run: |
|
||||||
|
pip install -U --cache-dir $TORCH_CACHE torch torchvision --index-url https://download.pytorch.org/whl/cu124
|
||||||
|
python -c "import torch; print('torch:', torch.__version__, torch)"
|
||||||
|
python -c "import torch; print('CUDA available:', torch.cuda.is_available())"
|
||||||
|
|
||||||
|
- name: Install deepspeed
|
||||||
|
run: |
|
||||||
|
pip install .[dev,autotuning]
|
||||||
|
ds_report
|
||||||
|
|
||||||
|
- name: Python environment
|
||||||
|
run: |
|
||||||
|
pip list
|
||||||
|
|
||||||
|
- name: HF Accelerate tests
|
||||||
|
run: |
|
||||||
|
unset TORCH_CUDA_ARCH_LIST # only jit compile for current arch
|
||||||
|
git clone https://github.com/huggingface/accelerate
|
||||||
|
cd accelerate
|
||||||
|
git rev-parse --short HEAD
|
||||||
|
|
||||||
|
# temp workaround until this is resolved https://github.com/huggingface/accelerate/issues/3676
|
||||||
|
pip install datasets==3.6.0
|
||||||
|
|
||||||
|
# installing dependencies
|
||||||
|
pip install .[testing]
|
||||||
|
# force protobuf version due to issues
|
||||||
|
pip install "protobuf<4.21.0"
|
||||||
|
pip list
|
||||||
|
pytest $PYTEST_OPTS --color=yes --durations=0 --verbose tests/deepspeed
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
name: nv-ds-chat
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
dse_branch:
|
||||||
|
description: 'DeepSpeedExamples Branch'
|
||||||
|
required: false
|
||||||
|
default: 'master'
|
||||||
|
type: string
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/nv-ds-chat.yml"
|
||||||
|
- "deepspeed/runtime/zero/stage_1_and_2.py"
|
||||||
|
- "deepspeed/runtime/zero/stage3.py"
|
||||||
|
- "deepspeed/runtime/hybrid_engine.py"
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
unit-tests:
|
||||||
|
name: nv-ds-chat / DeepSpeed-Chat tests
|
||||||
|
runs-on: [self-hosted, nvidia, cu124, v100]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- id: setup-venv
|
||||||
|
uses: ./.github/workflows/setup-venv
|
||||||
|
|
||||||
|
- name: Install pytorch
|
||||||
|
run: |
|
||||||
|
pip install -U --cache-dir $TORCH_CACHE torch torchvision --index-url https://download.pytorch.org/whl/cu124
|
||||||
|
python -c "import torch; print('torch:', torch.__version__, torch)"
|
||||||
|
python -c "import torch; print('CUDA available:', torch.cuda.is_available())"
|
||||||
|
|
||||||
|
- name: Install deepspeed
|
||||||
|
run: |
|
||||||
|
pip install .[dev]
|
||||||
|
pip install transformers==4.48.3
|
||||||
|
ds_report
|
||||||
|
|
||||||
|
- name: Install deepspeed-chat
|
||||||
|
run: |
|
||||||
|
BRANCH="master"
|
||||||
|
if [[ ! -z "${{ github.event.inputs.dse_branch }}" ]]; then
|
||||||
|
BRANCH="${{ github.event.inputs.dse_branch }}"
|
||||||
|
fi
|
||||||
|
echo "DeepSpeedExamples Branch: $BRANCH"
|
||||||
|
git clone -b $BRANCH https://github.com/deepspeedai/DeepSpeedExamples.git
|
||||||
|
cd DeepSpeedExamples/applications/DeepSpeed-Chat
|
||||||
|
pip install -r requirements.txt
|
||||||
|
pip install -e .
|
||||||
|
|
||||||
|
- name: Python environment
|
||||||
|
run: |
|
||||||
|
pip list
|
||||||
|
|
||||||
|
- name: DS-Chat unit tests
|
||||||
|
run: |
|
||||||
|
cd DeepSpeedExamples/applications/DeepSpeed-Chat
|
||||||
|
unset TORCH_CUDA_ARCH_LIST # only jit compile for current arch
|
||||||
|
unset NCCL_DEBUG
|
||||||
|
cd tests
|
||||||
|
pytest $PYTEST_OPTS ./
|
||||||
|
|
||||||
|
- name: Open GitHub issue if nightly CI fails
|
||||||
|
if: ${{ failure() && (github.event_name == 'schedule') }}
|
||||||
|
uses: JasonEtco/create-an-issue@v2
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
filename: .github/ISSUE_TEMPLATE/ci_failure_report.md
|
||||||
|
update_existing: true
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
name: nv-flash-attn
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- 'deepspeed/sequence/**'
|
||||||
|
- 'tests/unit/sequence_parallelism/**'
|
||||||
|
- '.github/workflows/nv-flash-attn.yml'
|
||||||
|
schedule:
|
||||||
|
- cron: "0 0 * * *"
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
unit-tests:
|
||||||
|
name: nv-flash-attn / sequence parallelism tests
|
||||||
|
runs-on: [self-hosted, nvidia, a6000]
|
||||||
|
container:
|
||||||
|
image: nvcr.io/nvidia/pytorch:24.12-py3
|
||||||
|
ports:
|
||||||
|
- 80
|
||||||
|
options: --gpus all --shm-size "8G"
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Check container state
|
||||||
|
run: |
|
||||||
|
ldd --version
|
||||||
|
nvcc --version
|
||||||
|
nvidia-smi
|
||||||
|
python -c "import torch; print('torch:', torch.__version__, torch)"
|
||||||
|
python -c "import torch; print('CUDA available:', torch.cuda.is_available())"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- name: Install deepspeed
|
||||||
|
run: |
|
||||||
|
python -m pip install .[dev]
|
||||||
|
ds_report
|
||||||
|
|
||||||
|
# install transformers after deepspeed so that the right version of transformers is installed
|
||||||
|
- name: Install transformers
|
||||||
|
run: |
|
||||||
|
python -m pip install transformers==4.50.0
|
||||||
|
|
||||||
|
- name: Install FlashAttention
|
||||||
|
run: |
|
||||||
|
python -m pip install flash-attn
|
||||||
|
- name: Python environment
|
||||||
|
run: |
|
||||||
|
python -m pip list
|
||||||
|
- name: Unit tests
|
||||||
|
run: |
|
||||||
|
unset TORCH_CUDA_ARCH_LIST # only jit compile for current arch
|
||||||
|
cd tests
|
||||||
|
python -m pytest --color=yes --durations=0 --verbose -rF unit/sequence_parallelism/test_ulysses.py --torch_ver="2.6" --cuda_ver="12"
|
||||||
|
- name: Open GitHub issue if nightly CI fails
|
||||||
|
if: ${{ failure() && (github.event_name == 'schedule') }}
|
||||||
|
uses: JasonEtco/create-an-issue@v2
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
filename: .github/ISSUE_TEMPLATE/ci_failure_report.md
|
||||||
|
update_existing: true
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
name: nv-inference
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/nv-inference.yml'
|
||||||
|
- 'requirements/**'
|
||||||
|
- 'deepspeed/__init__.py'
|
||||||
|
- 'deepspeed/inference/**'
|
||||||
|
- '!deepspeed/inference/v2/**' # exclude v2 dir
|
||||||
|
- 'tests/unit/inference/**'
|
||||||
|
- '!tests/unit/inference/v2/**' # exclude v2 tests dir
|
||||||
|
merge_group:
|
||||||
|
branches: [ master ]
|
||||||
|
schedule:
|
||||||
|
- cron: "0 0 * * *"
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
unit-tests:
|
||||||
|
name: nv-inference / inference tests
|
||||||
|
runs-on: [self-hosted, nvidia, cu124, v100]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- id: setup-venv
|
||||||
|
uses: ./.github/workflows/setup-venv
|
||||||
|
|
||||||
|
- name: Install pytorch
|
||||||
|
run: |
|
||||||
|
pip install -U --cache-dir $TORCH_CACHE torch==2.1.2 torchvision==0.16.2 --index-url https://download.pytorch.org/whl/cu124
|
||||||
|
python -c "import torch; print('torch:', torch.__version__, torch)"
|
||||||
|
python -c "import torch; print('CUDA available:', torch.cuda.is_available())"
|
||||||
|
|
||||||
|
- name: Install transformers
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/huggingface/transformers
|
||||||
|
cd transformers
|
||||||
|
#git checkout f370bebdc
|
||||||
|
git rev-parse --short HEAD
|
||||||
|
pip install .
|
||||||
|
|
||||||
|
- name: Install deepspeed
|
||||||
|
run: |
|
||||||
|
DS_ACCELERATOR=cpu pip install .[dev,1bit,autotuning,inf]
|
||||||
|
#pip install .[dev,1bit,autotuning,inf,triton]
|
||||||
|
ds_report
|
||||||
|
|
||||||
|
- name: Python environment
|
||||||
|
run: |
|
||||||
|
pip list
|
||||||
|
|
||||||
|
- name: Unit tests
|
||||||
|
run: |
|
||||||
|
unset TORCH_CUDA_ARCH_LIST # only jit compile for current arch
|
||||||
|
cd tests
|
||||||
|
#pytest $PYTEST_OPTS -m 'seq_inference' unit/ --torch_ver="2.1" --cuda_ver="12.4"
|
||||||
|
pytest $PYTEST_OPTS -m 'inference_ops' unit/ --torch_ver="2.1" --cuda_ver="12.4"
|
||||||
|
pytest $PYTEST_OPTS --forked -n 4 -m 'inference' unit/ --torch_ver="2.1" --cuda_ver="12.4"
|
||||||
|
# run ds_report again to check updated op list
|
||||||
|
ds_report
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
# name: nv-lightning-v100
|
||||||
|
|
||||||
|
# disabled as the v100s are no more - need to port to modal while removing v100
|
||||||
|
|
||||||
|
# on:
|
||||||
|
# workflow_dispatch:
|
||||||
|
# pull_request:
|
||||||
|
# paths-ignore:
|
||||||
|
# - 'docs/**'
|
||||||
|
# - 'blogs/**'
|
||||||
|
# - 'deepspeed/inference/v2/**'
|
||||||
|
# - 'tests/unit/inference/v2/**'
|
||||||
|
# merge_group:
|
||||||
|
# branches: [ master ]
|
||||||
|
# schedule:
|
||||||
|
# - cron: "0 0 * * *"
|
||||||
|
|
||||||
|
# concurrency:
|
||||||
|
# group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
# cancel-in-progress: true
|
||||||
|
|
||||||
|
# jobs:
|
||||||
|
# unit-tests:
|
||||||
|
# runs-on: [self-hosted, nvidia, cu124, v100]
|
||||||
|
|
||||||
|
# steps:
|
||||||
|
# - uses: actions/checkout@v4
|
||||||
|
|
||||||
|
# - id: setup-venv
|
||||||
|
# uses: ./.github/workflows/setup-venv
|
||||||
|
|
||||||
|
# - name: Install pytorch
|
||||||
|
# run: |
|
||||||
|
# pip install -U --cache-dir $TORCH_CACHE torch torchvision --index-url https://download.pytorch.org/whl/cu124
|
||||||
|
# python -c "import torch; print('torch:', torch.__version__, torch)"
|
||||||
|
# python -c "import torch; print('CUDA available:', torch.cuda.is_available())"
|
||||||
|
|
||||||
|
# - name: Install deepspeed
|
||||||
|
# run: |
|
||||||
|
# pip install .[dev,autotuning]
|
||||||
|
# ds_report
|
||||||
|
|
||||||
|
# - name: Python environment
|
||||||
|
# run: |
|
||||||
|
# pip list
|
||||||
|
|
||||||
|
# - name: PyTorch Lightning Tests
|
||||||
|
# run: |
|
||||||
|
# unset TORCH_CUDA_ARCH_LIST # only jit compile for current arch
|
||||||
|
# pip install pytorch-lightning
|
||||||
|
# pip install "protobuf<4.21.0"
|
||||||
|
# cd tests
|
||||||
|
# pytest $PYTEST_OPTS lightning/
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
name: nv-mii
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
unit-tests:
|
||||||
|
runs-on: [self-hosted, nvidia, cu124, v100]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- id: setup-venv
|
||||||
|
uses: ./.github/workflows/setup-venv
|
||||||
|
|
||||||
|
- name: Install pytorch
|
||||||
|
run: |
|
||||||
|
pip3 install -U --cache-dir $TORCH_CACHE torch torchvision --index-url https://download.pytorch.org/whl/cu124
|
||||||
|
python -c "import torch; print('torch:', torch.__version__, torch)"
|
||||||
|
python -c "import torch; print('CUDA available:', torch.cuda.is_available())"
|
||||||
|
|
||||||
|
- name: Install deepspeed
|
||||||
|
run: |
|
||||||
|
pip install .[dev]
|
||||||
|
ds_report
|
||||||
|
|
||||||
|
# install transformers after deepspeed so that the right version of transformers is installed
|
||||||
|
- name: Install transformers
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/huggingface/transformers
|
||||||
|
cd transformers
|
||||||
|
# if needed switch to the last known good SHA until transformers@master is fixed
|
||||||
|
git checkout v4.42.4
|
||||||
|
git rev-parse --short HEAD
|
||||||
|
pip install .
|
||||||
|
|
||||||
|
- name: Python environment
|
||||||
|
run: |
|
||||||
|
pip list
|
||||||
|
|
||||||
|
- name: MII unit tests
|
||||||
|
run: |
|
||||||
|
BRANCH="main"
|
||||||
|
if [[ ! -z "${{ github.event.inputs.mii_branch }}" ]]; then
|
||||||
|
BRANCH="${{ github.event.inputs.mii_branch }}"
|
||||||
|
fi
|
||||||
|
echo "Cloning DeepSpeed-MII branch: $BRANCH"
|
||||||
|
git clone -b $BRANCH --depth=1 https://github.com/deepspeedai/DeepSpeed-MII.git
|
||||||
|
cd DeepSpeed-MII
|
||||||
|
pip install .[dev]
|
||||||
|
unset TORCH_CUDA_ARCH_LIST # only jit compile for current arch
|
||||||
|
cd tests/legacy
|
||||||
|
pytest $PYTEST_OPTS --forked -m "deepspeed" ./
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
name: nv-nightly
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
unit-tests:
|
||||||
|
runs-on: [self-hosted, nvidia, cu124, v100]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- id: setup-venv
|
||||||
|
uses: ./.github/workflows/setup-venv
|
||||||
|
|
||||||
|
- name: Install pytorch
|
||||||
|
run: |
|
||||||
|
pip install -U --cache-dir $TORCH_CACHE torch torchvision --index-url https://download.pytorch.org/whl/cu124
|
||||||
|
python -c "import torch; print('torch:', torch.__version__, torch)"
|
||||||
|
python -c "import torch; print('CUDA available:', torch.cuda.is_available())"
|
||||||
|
|
||||||
|
- name: Install transformers
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/huggingface/transformers
|
||||||
|
cd transformers
|
||||||
|
# if needed switch to the last known good SHA until transformers@master is fixed
|
||||||
|
git checkout v4.42.4
|
||||||
|
git rev-parse --short HEAD
|
||||||
|
pip install .
|
||||||
|
|
||||||
|
- name: Install datasets
|
||||||
|
run: |
|
||||||
|
pip install datasets
|
||||||
|
|
||||||
|
- name: Install deepspeed
|
||||||
|
run: |
|
||||||
|
pip install .[dev,1bit,autotuning,inf]
|
||||||
|
ds_report
|
||||||
|
|
||||||
|
- name: Python environment
|
||||||
|
run: |
|
||||||
|
pip list
|
||||||
|
|
||||||
|
- name: Unit tests
|
||||||
|
run: |
|
||||||
|
unset TORCH_CUDA_ARCH_LIST # only jit compile for current arch
|
||||||
|
cd tests
|
||||||
|
pytest $PYTEST_OPTS --forked -m 'nightly' unit/ --torch_ver="2.6" --cuda_ver="12.4"
|
||||||
|
|
||||||
|
- name: Open GitHub issue if nightly CI fails
|
||||||
|
if: ${{ failure() && (github.event_name == 'schedule') }}
|
||||||
|
uses: JasonEtco/create-an-issue@v2
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
filename: .github/ISSUE_TEMPLATE/ci_failure_report.md
|
||||||
|
update_existing: true
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
name: nv-pre-compile-ops
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
'**'
|
||||||
|
merge_group:
|
||||||
|
branches: [ master ]
|
||||||
|
schedule:
|
||||||
|
- cron: "0 0 * * *"
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-paths:
|
||||||
|
name: nv-pre-compile-ops / check paths
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: read
|
||||||
|
outputs:
|
||||||
|
should_run: ${{ steps.non_pr.outputs.should_run || steps.filter.outputs.run_tests }}
|
||||||
|
steps:
|
||||||
|
- id: non_pr
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
run: echo "should_run=true" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
|
||||||
|
- uses: dorny/paths-filter@v3
|
||||||
|
id: filter
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
with:
|
||||||
|
predicate-quantifier: every
|
||||||
|
filters: |
|
||||||
|
run_tests:
|
||||||
|
- '**'
|
||||||
|
- '!docs/**'
|
||||||
|
- '!blogs/**'
|
||||||
|
- '!deepspeed/inference/v2/**'
|
||||||
|
- '!tests/unit/inference/v2/**'
|
||||||
|
|
||||||
|
unit-tests:
|
||||||
|
name: nv-pre-compile-ops / precompile ops
|
||||||
|
needs: check-paths
|
||||||
|
if: ${{ !cancelled() && (needs.check-paths.result != 'success' || needs.check-paths.outputs.should_run == 'true') }}
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
container:
|
||||||
|
image: nvidia/cuda:12.6.3-devel-ubuntu22.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Fail if path filter failed
|
||||||
|
if: needs.check-paths.result != 'success'
|
||||||
|
run: exit 1
|
||||||
|
|
||||||
|
- name: Install system dependencies
|
||||||
|
run: |
|
||||||
|
apt-get update && apt-get install -y git python3 python3-pip libaio-dev ninja-build
|
||||||
|
ln -sf /usr/bin/python3 /usr/bin/python
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install PyTorch
|
||||||
|
run: |
|
||||||
|
pip install torch==2.10.0 --index-url https://download.pytorch.org/whl/cu126
|
||||||
|
|
||||||
|
- name: environment
|
||||||
|
run: |
|
||||||
|
which python
|
||||||
|
python --version
|
||||||
|
python -c "import torch; print('torch:', torch.__version__, torch)"
|
||||||
|
#python -c "import torch; print('CUDA available:', torch.cuda.is_available())"
|
||||||
|
- name: Compile DeepSpeed Ops
|
||||||
|
run: |
|
||||||
|
DS_ACCELERATOR=cuda DS_ENABLE_NINJA=1 TORCH_CUDA_ARCH_LIST="7.0;7.5;8.0;8.6;8.9;9.0" DS_BUILD_OPS=1 DS_BUILD_SPARSE_ATTN=0 DS_BUILD_FP_QUANTIZER=0 DS_BUILD_CUTLASS_OPS=0 DS_BUILD_GDS=0 DS_BUILD_RAGGED_DEVICE_OPS=0 DS_BUILD_EVOFORMER_ATTN=0 DS_BUILD_DEEP_COMPILE=0 pip3 install .
|
||||||
|
- name: DS Report
|
||||||
|
run: |
|
||||||
|
DS_ACCELERATOR=cuda ds_report
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
name: nv-sd
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- "deepspeed/ops/transformer/inference/diffusers_**"
|
||||||
|
- "tests/unit/inference/test_stable_diffusion.py"
|
||||||
|
- "deepspeed/model_implementations/diffusers/unet.py"
|
||||||
|
- "deepspeed/model_implementations/diffusers/vae.py"
|
||||||
|
- "deepspeed/module_inject/containers/vae.py"
|
||||||
|
- "deepspeed/module_inject/containers/unet.py"
|
||||||
|
- ".github/workflows/nv-sd.yml"
|
||||||
|
- "requirements/requirements-sd.txt"
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
sd-tests:
|
||||||
|
name: nv-sd / stable diffusion tests
|
||||||
|
runs-on: [self-hosted, nvidia, a6000]
|
||||||
|
container:
|
||||||
|
image: nvcr.io/nvidia/pytorch:24.03-py3
|
||||||
|
ports:
|
||||||
|
- 80
|
||||||
|
options: --gpus all --shm-size "8G"
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Check container state
|
||||||
|
run: |
|
||||||
|
ldd --version
|
||||||
|
nvcc --version
|
||||||
|
nvidia-smi
|
||||||
|
python -c "import torch; print('torch:', torch.__version__, torch)"
|
||||||
|
python -c "import torch; print('CUDA available:', torch.cuda.is_available())"
|
||||||
|
- name: Install transformers
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/huggingface/transformers
|
||||||
|
cd transformers
|
||||||
|
git rev-parse --short HEAD
|
||||||
|
python -m pip install .
|
||||||
|
- name: Install deepspeed
|
||||||
|
run: |
|
||||||
|
pip install image-similarity-measures
|
||||||
|
python -m pip install opencv-python==4.6.* --force-reinstall
|
||||||
|
python -m pip install docutils==0.18.1 jinja2==3.0 urllib3==1.26.11 ninja
|
||||||
|
python -m pip install .[dev,1bit,autotuning,sd]
|
||||||
|
ds_report
|
||||||
|
- name: Python environment
|
||||||
|
run: |
|
||||||
|
python -m pip list
|
||||||
|
- name: Unit tests
|
||||||
|
run: |
|
||||||
|
unset TORCH_CUDA_ARCH_LIST # only jit compile for current arch
|
||||||
|
cd tests
|
||||||
|
python -m pytest --color=yes --durations=0 --verbose -rF -m 'stable_diffusion' -k "TestStableDiffusion" unit/ --torch_ver="2.3" --cuda_ver="12"
|
||||||
|
|
||||||
|
- name: Open GitHub issue if weekly CI fails
|
||||||
|
if: ${{ failure() && (github.event_name == 'schedule') }}
|
||||||
|
uses: JasonEtco/create-an-issue@v2
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
filename: .github/ISSUE_TEMPLATE/ci_failure_report.md
|
||||||
|
update_existing: true
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
name: nv-torch-latest-v100
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
unit-tests:
|
||||||
|
runs-on: [self-hosted, nvidia, cu124, v100]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- id: setup-venv
|
||||||
|
uses: ./.github/workflows/setup-venv
|
||||||
|
|
||||||
|
- name: Install pytorch
|
||||||
|
run: |
|
||||||
|
pip install -U --cache-dir $TORCH_CACHE torch torchvision --index-url https://download.pytorch.org/whl/cu124
|
||||||
|
python -c "import torch; print('torch:', torch.__version__, torch)"
|
||||||
|
python -c "import torch; print('CUDA available:', torch.cuda.is_available())"
|
||||||
|
|
||||||
|
- name: Install transformers
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/huggingface/transformers
|
||||||
|
cd transformers
|
||||||
|
# if needed switch to the last known good SHA until transformers@master is fixed
|
||||||
|
git checkout 981c276
|
||||||
|
git rev-parse --short HEAD
|
||||||
|
pip install .
|
||||||
|
|
||||||
|
- name: Install deepspeed
|
||||||
|
run: |
|
||||||
|
pip install .[dev,1bit,autotuning,deepcompile]
|
||||||
|
pip install pytest-timeout pytest-instafail
|
||||||
|
ds_report
|
||||||
|
|
||||||
|
- name: Python environment
|
||||||
|
run: |
|
||||||
|
pip list
|
||||||
|
|
||||||
|
- name: Unit tests
|
||||||
|
run: |
|
||||||
|
unset TORCH_CUDA_ARCH_LIST # only jit compile for current arch
|
||||||
|
cd tests
|
||||||
|
pytest -x $PYTEST_OPTS --instafail --timeout 600 --forked -n 8 unit/ --torch_ver="2.6" --cuda_ver="12.4"
|
||||||
|
pytest $PYTEST_OPTS --instafail --timeout 600 --forked -m 'sequential' unit/ --torch_ver="2.6" --cuda_ver="12.4"
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
name: nv-torch-nightly-v100
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
unit-tests:
|
||||||
|
runs-on: [self-hosted, nvidia, cu124, v100]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- id: setup-venv
|
||||||
|
uses: ./.github/workflows/setup-venv
|
||||||
|
|
||||||
|
- name: Install pytorch
|
||||||
|
run: |
|
||||||
|
pip install --pre torch torchvision --index-url https://download.pytorch.org/whl/nightly/cu124
|
||||||
|
python -c "import torch; print('torch:', torch.__version__, torch)"
|
||||||
|
python -c "import torch; print('CUDA available:', torch.cuda.is_available())"
|
||||||
|
|
||||||
|
- name: Install transformers
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/huggingface/transformers
|
||||||
|
cd transformers
|
||||||
|
# if needed switch to the last known good SHA until transformers@master is fixed
|
||||||
|
# git checkout 981c276
|
||||||
|
git rev-parse --short HEAD
|
||||||
|
pip install .
|
||||||
|
|
||||||
|
- name: Install deepspeed
|
||||||
|
run: |
|
||||||
|
pip install .[dev,1bit,autotuning]
|
||||||
|
ds_report
|
||||||
|
|
||||||
|
- name: Python environment
|
||||||
|
run: |
|
||||||
|
pip list
|
||||||
|
|
||||||
|
- name: Unit tests
|
||||||
|
run: |
|
||||||
|
unset TORCH_CUDA_ARCH_LIST # only jit compile for current arch
|
||||||
|
cd tests
|
||||||
|
pytest $PYTEST_OPTS --forked -n 8 unit/
|
||||||
|
pytest $PYTEST_OPTS --forked -m 'sequential' unit/
|
||||||
|
|
||||||
|
- name: Open GitHub issue if nightly CI fails
|
||||||
|
if: ${{ failure() && (github.event_name == 'schedule') }}
|
||||||
|
uses: JasonEtco/create-an-issue@v2
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
filename: .github/ISSUE_TEMPLATE/ci_failure_report.md
|
||||||
|
update_existing: true
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
name: nv-transformers-v100
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
unit-tests:
|
||||||
|
runs-on: [self-hosted, nvidia, cu124, v100]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- id: setup-venv
|
||||||
|
uses: ./.github/workflows/setup-venv
|
||||||
|
|
||||||
|
- name: Install pytorch
|
||||||
|
run: |
|
||||||
|
# use the same pytorch version as transformers CI
|
||||||
|
pip install -U --cache-dir $TORCH_CACHE torch==2.0.1+cu124 --index-url https://download.pytorch.org/whl/cu124
|
||||||
|
python -c "import torch; print('torch:', torch.__version__, torch)"
|
||||||
|
python -c "import torch; print('CUDA available:', torch.cuda.is_available())"
|
||||||
|
|
||||||
|
- name: Install transformers
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/huggingface/transformers
|
||||||
|
cd transformers
|
||||||
|
# if needed switch to the last known good SHA until transformers@master is fixed
|
||||||
|
git checkout e7e9261a2
|
||||||
|
git rev-parse --short HEAD
|
||||||
|
pip install .
|
||||||
|
|
||||||
|
- name: Install deepspeed
|
||||||
|
run: |
|
||||||
|
pip install .[dev,autotuning]
|
||||||
|
ds_report
|
||||||
|
|
||||||
|
- name: Python environment
|
||||||
|
run: |
|
||||||
|
pip list
|
||||||
|
|
||||||
|
- name: HF transformers tests
|
||||||
|
run: |
|
||||||
|
unset TORCH_CUDA_ARCH_LIST # only jit compile for current arch
|
||||||
|
cd transformers
|
||||||
|
pip install .[testing]
|
||||||
|
# find reqs used in ds integration tests
|
||||||
|
find examples/pytorch -regextype posix-egrep -regex '.*(language-modeling|question-answering|summarization|image-classification|text-classification|translation).*/requirements.txt' -exec grep -v 'torch' {} \; | xargs -I {} pip install --upgrade {}
|
||||||
|
# force protobuf version due to issues
|
||||||
|
pip install "protobuf<4.21.0"
|
||||||
|
pip list
|
||||||
|
WANDB_DISABLED=true RUN_SLOW=1 pytest $PYTEST_OPTS tests/deepspeed
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
name: python
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
'**'
|
||||||
|
merge_group:
|
||||||
|
branches: [ master ]
|
||||||
|
schedule:
|
||||||
|
- cron: "0 0 * * *"
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-paths:
|
||||||
|
name: python / check paths
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: read
|
||||||
|
outputs:
|
||||||
|
should_run: ${{ steps.non_pr.outputs.should_run || steps.filter.outputs.run_tests }}
|
||||||
|
steps:
|
||||||
|
- id: non_pr
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
run: echo "should_run=true" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
|
||||||
|
- uses: dorny/paths-filter@v3
|
||||||
|
id: filter
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
with:
|
||||||
|
predicate-quantifier: every
|
||||||
|
filters: |
|
||||||
|
run_tests:
|
||||||
|
- '**'
|
||||||
|
- '!docs/**'
|
||||||
|
- '!blogs/**'
|
||||||
|
|
||||||
|
unit-tests:
|
||||||
|
name: python / install smoke (Python ${{ matrix.pyVersion }})
|
||||||
|
needs: check-paths
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
pyVersion: ["3.10", "3.11", "3.12"]
|
||||||
|
fail-fast: false
|
||||||
|
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
container:
|
||||||
|
image: python:${{ matrix.pyVersion }}-slim
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Fail if path filter failed
|
||||||
|
if: needs.check-paths.result != 'success'
|
||||||
|
run: exit 1
|
||||||
|
|
||||||
|
- name: Skip ignored-path install smoke
|
||||||
|
if: needs.check-paths.outputs.should_run != 'true'
|
||||||
|
run: echo "Only ignored paths changed; install smoke intentionally skipped."
|
||||||
|
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
if: needs.check-paths.outputs.should_run == 'true'
|
||||||
|
|
||||||
|
- name: Install build dependencies
|
||||||
|
if: needs.check-paths.outputs.should_run == 'true'
|
||||||
|
run: |
|
||||||
|
apt-get update && apt-get install -y build-essential ninja-build
|
||||||
|
- name: environment
|
||||||
|
if: needs.check-paths.outputs.should_run == 'true'
|
||||||
|
run: |
|
||||||
|
which python
|
||||||
|
python --version
|
||||||
|
- name: Install PyTorch (CPU)
|
||||||
|
if: needs.check-paths.outputs.should_run == 'true'
|
||||||
|
run: |
|
||||||
|
pip install torch --index-url https://download.pytorch.org/whl/cpu
|
||||||
|
- name: Install deepspeed
|
||||||
|
if: needs.check-paths.outputs.should_run == 'true'
|
||||||
|
run: |
|
||||||
|
pip install .
|
||||||
|
- name: DS Report
|
||||||
|
if: needs.check-paths.outputs.should_run == 'true'
|
||||||
|
run: |
|
||||||
|
ds_report
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
name: Build and publish DeepSpeed release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*.*.*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
environment: release-env
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: "master"
|
||||||
|
- id: setup-venv
|
||||||
|
uses: ./.github/workflows/setup-venv
|
||||||
|
- name: Get release version from tag
|
||||||
|
run: |
|
||||||
|
echo "RELEASE_VERSION=${GITHUB_REF#refs/*/v}" >> $GITHUB_ENV
|
||||||
|
- name: Check release version
|
||||||
|
run: |
|
||||||
|
pip install packaging
|
||||||
|
python release/check_release_version.py --release_version ${{ env.RELEASE_VERSION }}
|
||||||
|
- name: Build DeepSpeed
|
||||||
|
run: |
|
||||||
|
pip install setuptools
|
||||||
|
pip install build
|
||||||
|
DS_BUILD_STRING=" " python -m build --sdist
|
||||||
|
- name: Publish to PyPI
|
||||||
|
uses: pypa/gh-action-pypi-publish@release/v1
|
||||||
|
with:
|
||||||
|
password: ${{ secrets.PYPI_API_TOKEN }}
|
||||||
|
repository-url: https://upload.pypi.org/legacy/
|
||||||
|
- name: Bump version
|
||||||
|
run: |
|
||||||
|
python release/bump_patch_version.py --current_version ${{ env.RELEASE_VERSION }}
|
||||||
|
- name: Create Pull Request
|
||||||
|
uses: peter-evans/create-pull-request@v6
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GH_PAT }}
|
||||||
|
add-paths: |
|
||||||
|
version.txt
|
||||||
|
body: |
|
||||||
|
**Auto-generated PR to update version.txt after a DeepSpeed release**
|
||||||
|
Released version - ${{ env.RELEASE_VERSION }}
|
||||||
|
Author - @${{ github.actor }}
|
||||||
|
branch: AutoPR/${{ env.RELEASE_VERSION }}
|
||||||
|
assignees: ${{ github.actor }}
|
||||||
|
title: "Update version.txt after ${{ env.RELEASE_VERSION }} release"
|
||||||
|
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
name: Create Virtual Environment
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- id: update-env
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
# Temporary disable nvme UTs
|
||||||
|
# sudo apt-get install -y libaio-dev
|
||||||
|
sudo apt remove -y libaio-dev
|
||||||
|
python -m pip install --user --upgrade pip
|
||||||
|
python -m pip install --user --upgrade virtualenv
|
||||||
|
shell: bash
|
||||||
|
- id: create-venv
|
||||||
|
run: |
|
||||||
|
rm -rf ./unit-test-venv
|
||||||
|
python -m venv unit-test-venv
|
||||||
|
source ./unit-test-venv/bin/activate
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install wheel # required after pip>=23.1
|
||||||
|
echo PATH=$PATH >> $GITHUB_ENV # Make it so venv is inherited for other steps
|
||||||
|
shell: bash
|
||||||
|
- id: set-env-vars
|
||||||
|
run: |
|
||||||
|
echo TEST_DATA_DIR=/blob/ >> $GITHUB_ENV
|
||||||
|
echo HF_HOME=/blob/hf_home/ >> $GITHUB_ENV
|
||||||
|
echo TORCH_EXTENSIONS_DIR=./torch-extensions/ >> $GITHUB_ENV
|
||||||
|
echo TORCH_CACHE=/blob/torch_cache/ >> $GITHUB_ENV
|
||||||
|
echo HF_DATASETS_CACHE=/blob/datasets_cache/ >> $GITHUB_ENV
|
||||||
|
echo MEGATRON_CKPT_DIR=/blob/megatron_ckpt/ >> $GITHUB_ENV
|
||||||
|
echo CRITIC_CKPT_DIR=/blob/step2_opt_125m_ckpt/ >> $GITHUB_ENV
|
||||||
|
echo PYTEST_OPTS="--maxfail=100 --color=yes --durations=0 --verbose -rF" >> $GITHUB_ENV
|
||||||
|
shell: bash
|
||||||
|
- id: print-env
|
||||||
|
run: |
|
||||||
|
which python
|
||||||
|
python --version
|
||||||
|
if [[ -z "${AISC_NODE_INSTANCE_ID}" ]]; then
|
||||||
|
echo "Not on self-hosted node"
|
||||||
|
else
|
||||||
|
echo "JobID: ${AISC_NODE_INSTANCE_ID}"
|
||||||
|
fi
|
||||||
|
if command -v nvidia-smi; then
|
||||||
|
nvidia-smi
|
||||||
|
which nvcc
|
||||||
|
nvcc --version
|
||||||
|
elif command -v rocm-smi; then
|
||||||
|
rocm-smi --showhw
|
||||||
|
which hipcc
|
||||||
|
hipcc --version
|
||||||
|
fi
|
||||||
|
shell: bash
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
name: xpu-compile
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 0 * * *"
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/xpu-compile.yml"
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
compile-tests:
|
||||||
|
name: xpu-compile / compile tests
|
||||||
|
runs-on: [self-hosted, intel, xpu]
|
||||||
|
container:
|
||||||
|
image: intel/oneapi-basekit:2025.0.2-0-devel-ubuntu22.04
|
||||||
|
ports:
|
||||||
|
- 80
|
||||||
|
options: --privileged -it --rm --device /dev/dri:/dev/dri -v /dev/dri/by-path:/dev/dri/by-path --ipc=host --cap-add=ALL
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install prerequisite
|
||||||
|
run: |
|
||||||
|
apt-get update
|
||||||
|
apt-get install clinfo libaio-dev python3-pip -y
|
||||||
|
pip install torch==2.10.0 torchvision torchaudio --index-url https://download.pytorch.org/whl/xpu
|
||||||
|
pip install py-cpuinfo numpy
|
||||||
|
pip install .[dev,autotuning]
|
||||||
|
|
||||||
|
- name: Check container state
|
||||||
|
run: |
|
||||||
|
ldd --version
|
||||||
|
ds_report
|
||||||
|
python3 -c "import torch; print('torch:', torch.__version__, torch)"
|
||||||
|
python3 -c "import torch; print('XPU available:', torch.xpu.is_available())"
|
||||||
|
python3 -c "from deepspeed.accelerator import get_accelerator; print('accelerator:', get_accelerator()._name)"
|
||||||
|
pip list
|
||||||
|
|
||||||
|
- name: Compile Status
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "# torch.compile graph breaks" >> $GITHUB_STEP_SUMMARY
|
||||||
|
export FI_HMEM=system
|
||||||
|
ulimit -n 1048575
|
||||||
|
cd tests/torch_compile
|
||||||
|
export ZE_AFFINITY_MASK=0,1
|
||||||
|
echo "## ZeRO stage 3" >> $GITHUB_STEP_SUMMARY
|
||||||
|
deepspeed test_compile.py --deepspeed_config ds_config_z3.json 2>&1 | tee log_z3.txt
|
||||||
|
# for each line start with 'dynamo_output', extract the second field and following fields and append to GITHUB_STEP_SUMMARY using awk
|
||||||
|
cat log_z3.txt | awk '/^dynamo_output/ {$1=""; print $0}' >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "## ZeRO stage 2" >> $GITHUB_STEP_SUMMARY
|
||||||
|
deepspeed test_compile.py --deepspeed_config ds_config_z2.json 2>&1 | tee log_z2.txt
|
||||||
|
cat log_z2.txt | awk '/^dynamo_output/ {$1=""; print $0}' >> $GITHUB_STEP_SUMMARY
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
name: xpu-max1100
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 0 * * *"
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/xpu-max1100.yml"
|
||||||
|
- "accelerator/xpu_accelerator.py"
|
||||||
|
- "accelerator/abstract_accelerator.py"
|
||||||
|
- "accelerator/cpu_accelerator.py"
|
||||||
|
- "accelerator/real_accelerator.py"
|
||||||
|
- "csrc/xpu/**"
|
||||||
|
- "deepspeed/runtime/engine.py"
|
||||||
|
- "deepspeed/runtime/bf16_optimizer.py"
|
||||||
|
- "deepspeed/runtime/zero/stage_1_and_2.py"
|
||||||
|
- "deepspeed/runtime/zero/stage3.py"
|
||||||
|
- "deepspeed/runtime/zero/partition_parameters.py"
|
||||||
|
- "deepspeed/runtime/zero/partitioned_param_coordinator.py"
|
||||||
|
- "deepspeed/runtime/zero/parameter_offload.py"
|
||||||
|
- "deepspeed/runtime/pipe/engine.py"
|
||||||
|
- "deepspeed/runtime/utils.py"
|
||||||
|
- "op_builder/xpu/**"
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
unit-tests:
|
||||||
|
name: xpu-max1100 / unit tests
|
||||||
|
runs-on: [self-hosted, intel, xpu]
|
||||||
|
container:
|
||||||
|
image: intel/oneapi-basekit:2025.0.2-0-devel-ubuntu22.04
|
||||||
|
ports:
|
||||||
|
- 80
|
||||||
|
options: --privileged -it --rm --device /dev/dri:/dev/dri -v /dev/dri/by-path:/dev/dri/by-path --ipc=host --cap-add=ALL
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install prerequisite
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y python3.11 python3.11-dev python3-pip clinfo libaio-dev
|
||||||
|
pip install --upgrade pip
|
||||||
|
pip install py-cpuinfo
|
||||||
|
pip install torch==2.10.0 torchvision torchaudio --index-url https://download.pytorch.org/whl/xpu
|
||||||
|
pip install .[dev,autotuning]
|
||||||
|
|
||||||
|
- name: Check container state
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
ldd --version
|
||||||
|
ds_report
|
||||||
|
python3 -c "import torch; print('torch:', torch.__version__, torch)"
|
||||||
|
python3 -c "import torch; print('XPU available:', torch.xpu.is_available())"
|
||||||
|
python3 -c "from deepspeed.accelerator import get_accelerator; print('accelerator:', get_accelerator()._name)"
|
||||||
|
pip list
|
||||||
|
|
||||||
|
- name: Unit tests
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
cd tests/unit
|
||||||
|
export FI_PROVIDER="tcp"
|
||||||
|
export I_MPI_SHM=off
|
||||||
|
pytest --verbose accelerator/*
|
||||||
|
pytest --verbose autotuning/*
|
||||||
|
pytest --verbose model_parallelism/*
|
||||||
|
pytest --verbose monitor/*
|
||||||
|
pytest --verbose utils/*
|
||||||
|
pytest --verbose runtime/test_ds_config_model.py
|
||||||
|
pytest --verbose runtime/pipe/test_pipe_schedule.py
|
||||||
|
pytest --verbose runtime/zero/test_zero_config.py
|
||||||
|
pytest --verbose runtime/zero/test_zero_tiled.py
|
||||||
|
pytest --verbose runtime/zero/test_zeropp.py
|
||||||
|
pytest --verbose runtime/test_autocast.py
|
||||||
|
pytest --verbose runtime/test_data.py
|
||||||
|
pytest --verbose runtime/zero/test_zero_dynamic_class.py
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
## Ignore Python compiled files
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
## Output of the diff-based test selector (ci/tests_fetcher.py)
|
||||||
|
ci/.test_selection/
|
||||||
|
|
||||||
|
## Ignore IDE-specific files and directories
|
||||||
|
# JetBrains IDE settings
|
||||||
|
.idea/
|
||||||
|
# Visual Studio Code settings
|
||||||
|
.vscode/
|
||||||
|
# Theia IDE settings
|
||||||
|
.theia/
|
||||||
|
|
||||||
|
## Ignore temporary and backup files
|
||||||
|
# General backup files
|
||||||
|
*~
|
||||||
|
# Vim swap files
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
## Ignore log files
|
||||||
|
*.log
|
||||||
|
|
||||||
|
## Ignore a specific generated file
|
||||||
|
deepspeed/git_version_info_installed.py
|
||||||
|
|
||||||
|
## Ignore Python bytecode cache
|
||||||
|
__pycache__
|
||||||
|
|
||||||
|
## Build + installation data
|
||||||
|
# Build artifacts
|
||||||
|
build/
|
||||||
|
# Distribution files
|
||||||
|
dist/
|
||||||
|
# Compiled shared objects
|
||||||
|
*.so
|
||||||
|
# Deepspeed package info
|
||||||
|
deepspeed.egg-info/
|
||||||
|
# Build information
|
||||||
|
build.txt
|
||||||
|
|
||||||
|
## Website generated files
|
||||||
|
# Jekyll generated site
|
||||||
|
docs/_site/
|
||||||
|
# Generated documentation
|
||||||
|
docs/build
|
||||||
|
docs/code-docs/source/_build
|
||||||
|
docs/code-docs/_build
|
||||||
|
docs/code-docs/build
|
||||||
|
# SASS cache
|
||||||
|
.sass-cache/
|
||||||
|
# Jekyll cache
|
||||||
|
.jekyll-cache/
|
||||||
|
.jekyll-metadata
|
||||||
|
|
||||||
|
## Testing data
|
||||||
|
# Saved checkpoints for testing
|
||||||
|
tests/unit/saved_checkpoint/
|
||||||
|
|
||||||
|
# HIP files created during AMD compilation
|
||||||
|
*_hip.cpp
|
||||||
|
*_hip.h
|
||||||
|
*.hip
|
||||||
|
*.cuh
|
||||||
|
*hip_layers.h
|
||||||
|
|
||||||
|
# virtual env directory for format
|
||||||
|
venv
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
repos:
|
||||||
|
- repo: meta
|
||||||
|
hooks:
|
||||||
|
- id: check-hooks-apply
|
||||||
|
- id: check-useless-excludes
|
||||||
|
|
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
rev: v5.0.0
|
||||||
|
hooks:
|
||||||
|
- id: check-case-conflict
|
||||||
|
- id: check-json
|
||||||
|
- id: check-symlinks
|
||||||
|
- id: check-yaml
|
||||||
|
- id: destroyed-symlinks
|
||||||
|
- id: end-of-file-fixer
|
||||||
|
exclude: docs/CNAME
|
||||||
|
- id: fix-byte-order-marker
|
||||||
|
- id: fix-encoding-pragma
|
||||||
|
args: [--remove]
|
||||||
|
- id: mixed-line-ending
|
||||||
|
args: [--fix=lf]
|
||||||
|
- id: requirements-txt-fixer
|
||||||
|
- id: trailing-whitespace
|
||||||
|
|
||||||
|
- repo: https://github.com/google/yapf
|
||||||
|
rev: v0.40.0
|
||||||
|
hooks:
|
||||||
|
- id: yapf
|
||||||
|
|
||||||
|
- repo: https://gitlab.com/daverona/pre-commit/cpp
|
||||||
|
rev: 0.8.0
|
||||||
|
hooks:
|
||||||
|
- id: clang-format # formatter of C/C++ code based on a style guide: LLVM, Google, Chromium, Mozilla, and WebKit available
|
||||||
|
args: []
|
||||||
|
|
||||||
|
- repo: local
|
||||||
|
hooks:
|
||||||
|
- id: check-torchdist
|
||||||
|
name: check-torchdist
|
||||||
|
entry: ./scripts/check-torchdist.py
|
||||||
|
language: python
|
||||||
|
exclude: ^(deepspeed/comm/|docs/|benchmarks/|scripts/check-torchdist.py|deepspeed/moe/sharded_moe.py|deepspeed/runtime/comm/coalesced_collectives.py|deepspeed/elasticity/elastic_agent.py|deepspeed/launcher/launch.py|tests/unit/comm/test_dist.py)
|
||||||
|
# Specific deepspeed/ files are excluded for now until we wrap ProcessGroup in deepspeed.comm
|
||||||
|
|
||||||
|
- repo: local
|
||||||
|
hooks:
|
||||||
|
- id: check-license
|
||||||
|
name: check-license
|
||||||
|
entry: ./scripts/check-license.py
|
||||||
|
language: python
|
||||||
|
files: \.(py|c|cpp|cu|cc|h|hpp|cuh|hip|tr)$
|
||||||
|
exclude: ^(deepspeed/inference/v2/kernels/ragged_ops/blocked_flash|deepspeed/inference/v2/kernels/cutlass_ops/grouped_gemm)
|
||||||
|
|
||||||
|
- repo: https://github.com/codespell-project/codespell
|
||||||
|
rev: v2.1.0
|
||||||
|
hooks:
|
||||||
|
- id: codespell
|
||||||
|
args: [
|
||||||
|
# Do not check files that are automatically generated
|
||||||
|
'--skip=docs/Gemfile.lock,tests/unit/gpt2-merges.txt,tests/unit/gpt2-vocab.json',
|
||||||
|
'--ignore-regex=\\n', # Do not count the 'n' in an escaped newline as part of a word
|
||||||
|
'--ignore-words-list=youn,unsupport,noe,cann', # Word used in error messages that need rewording
|
||||||
|
--check-filenames,
|
||||||
|
--check-hidden
|
||||||
|
]
|
||||||
|
|
||||||
|
- repo: https://github.com/pycqa/flake8
|
||||||
|
rev: 5.0.4
|
||||||
|
hooks:
|
||||||
|
- id: flake8
|
||||||
|
args: ['--config=.flake8']
|
||||||
|
|
||||||
|
- repo: local
|
||||||
|
hooks:
|
||||||
|
- id: check-torchcuda
|
||||||
|
name: check-torchcuda
|
||||||
|
entry: ./scripts/check-torchcuda.py
|
||||||
|
language: python
|
||||||
|
exclude: ^(.github/workflows/|scripts/check-torchcuda.py|docs/_tutorials/accelerator-abstraction-interface.md|docs/_tutorials/deepnvme.md|accelerator/cuda_accelerator.py|deepspeed/inference/engine.py|deepspeed/model_implementations/transformers/clip_encoder.py|deepspeed/model_implementations/diffusers/vae.py|deepspeed/model_implementations/diffusers/unet.py|op_builder/spatial_inference.py|op_builder/transformer_inference.py|op_builder/builder.py|setup.py|tests/unit/ops/sparse_attention/test_sparse_attention.py)
|
||||||
|
# Specific deepspeed/ files are excluded for now until we wrap ProcessGroup in deepspeed.comm
|
||||||
|
|
||||||
|
- repo: local
|
||||||
|
hooks:
|
||||||
|
- id: check-extraindexurl
|
||||||
|
name: check-extraindexurl
|
||||||
|
entry: ./scripts/check-extraindexurl.py
|
||||||
|
language: python
|
||||||
|
files: \.(yml|yaml|sh|py)$
|
||||||
|
exclude: ^(scripts/check-extraindexurl.py)
|
||||||
@@ -0,0 +1,581 @@
|
|||||||
|
[MASTER]
|
||||||
|
|
||||||
|
# A comma-separated list of package or module names from where C extensions may
|
||||||
|
# be loaded. Extensions are loading into the active Python interpreter and may
|
||||||
|
# run arbitrary code.
|
||||||
|
extension-pkg-whitelist=
|
||||||
|
|
||||||
|
# Add files or directories to the blacklist. They should be base names, not
|
||||||
|
# paths.
|
||||||
|
ignore=CVS
|
||||||
|
|
||||||
|
# Add files or directories matching the regex patterns to the blacklist. The
|
||||||
|
# regex matches against base names, not paths.
|
||||||
|
ignore-patterns=
|
||||||
|
|
||||||
|
# Python code to execute, usually for sys.path manipulation such as
|
||||||
|
# pygtk.require().
|
||||||
|
#init-hook=
|
||||||
|
|
||||||
|
# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
|
||||||
|
# number of processors available to use.
|
||||||
|
jobs=1
|
||||||
|
|
||||||
|
# Control the amount of potential inferred values when inferring a single
|
||||||
|
# object. This can help the performance when dealing with large functions or
|
||||||
|
# complex, nested conditions.
|
||||||
|
limit-inference-results=100
|
||||||
|
|
||||||
|
# List of plugins (as comma separated values of python module names) to load,
|
||||||
|
# usually to register additional checkers.
|
||||||
|
load-plugins=
|
||||||
|
|
||||||
|
# Pickle collected data for later comparisons.
|
||||||
|
persistent=yes
|
||||||
|
|
||||||
|
# Specify a configuration file.
|
||||||
|
#rcfile=
|
||||||
|
|
||||||
|
# When enabled, pylint would attempt to guess common misconfiguration and emit
|
||||||
|
# user-friendly hints instead of false-positive error messages.
|
||||||
|
suggestion-mode=yes
|
||||||
|
|
||||||
|
# Allow loading of arbitrary C extensions. Extensions are imported into the
|
||||||
|
# active Python interpreter and may run arbitrary code.
|
||||||
|
unsafe-load-any-extension=no
|
||||||
|
|
||||||
|
|
||||||
|
[MESSAGES CONTROL]
|
||||||
|
|
||||||
|
# Only show warnings with the listed confidence levels. Leave empty to show
|
||||||
|
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED.
|
||||||
|
confidence=
|
||||||
|
|
||||||
|
# Disable the message, report, category or checker with the given id(s). You
|
||||||
|
# can either give multiple identifiers separated by comma (,) or put this
|
||||||
|
# option multiple times (only on the command line, not in the configuration
|
||||||
|
# file where it should appear only once). You can also use "--disable=all" to
|
||||||
|
# disable everything first and then re-enable specific checks. For example, if
|
||||||
|
# you want to run only the similarities checker, you can use "--disable=all
|
||||||
|
# --enable=similarities". If you want to run only the classes checker, but have
|
||||||
|
# no Warning level messages displayed, use "--disable=all --enable=classes
|
||||||
|
# --disable=W".
|
||||||
|
disable=print-statement,
|
||||||
|
parameter-unpacking,
|
||||||
|
unpacking-in-except,
|
||||||
|
old-raise-syntax,
|
||||||
|
backtick,
|
||||||
|
long-suffix,
|
||||||
|
old-ne-operator,
|
||||||
|
old-octal-literal,
|
||||||
|
import-star-module-level,
|
||||||
|
non-ascii-bytes-literal,
|
||||||
|
raw-checker-failed,
|
||||||
|
bad-inline-option,
|
||||||
|
locally-disabled,
|
||||||
|
file-ignored,
|
||||||
|
suppressed-message,
|
||||||
|
useless-suppression,
|
||||||
|
deprecated-pragma,
|
||||||
|
use-symbolic-message-instead,
|
||||||
|
apply-builtin,
|
||||||
|
basestring-builtin,
|
||||||
|
buffer-builtin,
|
||||||
|
cmp-builtin,
|
||||||
|
coerce-builtin,
|
||||||
|
execfile-builtin,
|
||||||
|
file-builtin,
|
||||||
|
long-builtin,
|
||||||
|
raw_input-builtin,
|
||||||
|
reduce-builtin,
|
||||||
|
standarderror-builtin,
|
||||||
|
unicode-builtin,
|
||||||
|
xrange-builtin,
|
||||||
|
coerce-method,
|
||||||
|
delslice-method,
|
||||||
|
getslice-method,
|
||||||
|
setslice-method,
|
||||||
|
no-absolute-import,
|
||||||
|
old-division,
|
||||||
|
dict-iter-method,
|
||||||
|
dict-view-method,
|
||||||
|
next-method-called,
|
||||||
|
metaclass-assignment,
|
||||||
|
indexing-exception,
|
||||||
|
raising-string,
|
||||||
|
reload-builtin,
|
||||||
|
oct-method,
|
||||||
|
hex-method,
|
||||||
|
nonzero-method,
|
||||||
|
cmp-method,
|
||||||
|
input-builtin,
|
||||||
|
round-builtin,
|
||||||
|
intern-builtin,
|
||||||
|
unichr-builtin,
|
||||||
|
map-builtin-not-iterating,
|
||||||
|
zip-builtin-not-iterating,
|
||||||
|
range-builtin-not-iterating,
|
||||||
|
filter-builtin-not-iterating,
|
||||||
|
using-cmp-argument,
|
||||||
|
eq-without-hash,
|
||||||
|
div-method,
|
||||||
|
idiv-method,
|
||||||
|
rdiv-method,
|
||||||
|
exception-message-attribute,
|
||||||
|
invalid-str-codec,
|
||||||
|
sys-max-int,
|
||||||
|
bad-python3-import,
|
||||||
|
deprecated-string-function,
|
||||||
|
deprecated-str-translate-call,
|
||||||
|
deprecated-itertools-function,
|
||||||
|
deprecated-types-field,
|
||||||
|
next-method-defined,
|
||||||
|
dict-items-not-iterating,
|
||||||
|
dict-keys-not-iterating,
|
||||||
|
dict-values-not-iterating,
|
||||||
|
deprecated-operator-function,
|
||||||
|
deprecated-urllib-function,
|
||||||
|
xreadlines-attribute,
|
||||||
|
deprecated-sys-function,
|
||||||
|
exception-escape,
|
||||||
|
comprehension-escape
|
||||||
|
|
||||||
|
# Enable the message, report, category or checker with the given id(s). You can
|
||||||
|
# either give multiple identifier separated by comma (,) or put this option
|
||||||
|
# multiple time (only on the command line, not in the configuration file where
|
||||||
|
# it should appear only once). See also the "--disable" option for examples.
|
||||||
|
enable=c-extension-no-member
|
||||||
|
|
||||||
|
|
||||||
|
[REPORTS]
|
||||||
|
|
||||||
|
# Python expression which should return a score less than or equal to 10. You
|
||||||
|
# have access to the variables 'error', 'warning', 'refactor', and 'convention'
|
||||||
|
# which contain the number of messages in each category, as well as 'statement'
|
||||||
|
# which is the total number of statements analyzed. This score is used by the
|
||||||
|
# global evaluation report (RP0004).
|
||||||
|
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
|
||||||
|
|
||||||
|
# Template used to display messages. This is a python new-style format string
|
||||||
|
# used to format the message information. See doc for all details.
|
||||||
|
#msg-template=
|
||||||
|
|
||||||
|
# Set the output format. Available formats are text, parseable, colorized, json
|
||||||
|
# and msvs (visual studio). You can also give a reporter class, e.g.
|
||||||
|
# mypackage.mymodule.MyReporterClass.
|
||||||
|
output-format=text
|
||||||
|
|
||||||
|
# Tells whether to display a full report or only the messages.
|
||||||
|
reports=no
|
||||||
|
|
||||||
|
# Activate the evaluation score.
|
||||||
|
score=yes
|
||||||
|
|
||||||
|
|
||||||
|
[REFACTORING]
|
||||||
|
|
||||||
|
# Maximum number of nested blocks for function / method body
|
||||||
|
max-nested-blocks=5
|
||||||
|
|
||||||
|
# Complete name of functions that never returns. When checking for
|
||||||
|
# inconsistent-return-statements if a never returning function is called then
|
||||||
|
# it will be considered as an explicit return statement and no message will be
|
||||||
|
# printed.
|
||||||
|
never-returning-functions=sys.exit
|
||||||
|
|
||||||
|
|
||||||
|
[BASIC]
|
||||||
|
|
||||||
|
# Naming style matching correct argument names.
|
||||||
|
argument-naming-style=snake_case
|
||||||
|
|
||||||
|
# Regular expression matching correct argument names. Overrides argument-
|
||||||
|
# naming-style.
|
||||||
|
#argument-rgx=
|
||||||
|
|
||||||
|
# Naming style matching correct attribute names.
|
||||||
|
attr-naming-style=snake_case
|
||||||
|
|
||||||
|
# Regular expression matching correct attribute names. Overrides attr-naming-
|
||||||
|
# style.
|
||||||
|
#attr-rgx=
|
||||||
|
|
||||||
|
# Bad variable names which should always be refused, separated by a comma.
|
||||||
|
bad-names=foo,
|
||||||
|
bar,
|
||||||
|
baz,
|
||||||
|
toto,
|
||||||
|
tutu,
|
||||||
|
tata
|
||||||
|
|
||||||
|
# Naming style matching correct class attribute names.
|
||||||
|
class-attribute-naming-style=any
|
||||||
|
|
||||||
|
# Regular expression matching correct class attribute names. Overrides class-
|
||||||
|
# attribute-naming-style.
|
||||||
|
#class-attribute-rgx=
|
||||||
|
|
||||||
|
# Naming style matching correct class names.
|
||||||
|
class-naming-style=PascalCase
|
||||||
|
|
||||||
|
# Regular expression matching correct class names. Overrides class-naming-
|
||||||
|
# style.
|
||||||
|
#class-rgx=
|
||||||
|
|
||||||
|
# Naming style matching correct constant names.
|
||||||
|
const-naming-style=UPPER_CASE
|
||||||
|
|
||||||
|
# Regular expression matching correct constant names. Overrides const-naming-
|
||||||
|
# style.
|
||||||
|
#const-rgx=
|
||||||
|
|
||||||
|
# Minimum line length for functions/classes that require docstrings, shorter
|
||||||
|
# ones are exempt.
|
||||||
|
docstring-min-length=-1
|
||||||
|
|
||||||
|
# Naming style matching correct function names.
|
||||||
|
function-naming-style=snake_case
|
||||||
|
|
||||||
|
# Regular expression matching correct function names. Overrides function-
|
||||||
|
# naming-style.
|
||||||
|
#function-rgx=
|
||||||
|
|
||||||
|
# Good variable names which should always be accepted, separated by a comma.
|
||||||
|
good-names=i,
|
||||||
|
j,
|
||||||
|
k,
|
||||||
|
ex,
|
||||||
|
Run,
|
||||||
|
_
|
||||||
|
|
||||||
|
# Include a hint for the correct naming format with invalid-name.
|
||||||
|
include-naming-hint=no
|
||||||
|
|
||||||
|
# Naming style matching correct inline iteration names.
|
||||||
|
inlinevar-naming-style=any
|
||||||
|
|
||||||
|
# Regular expression matching correct inline iteration names. Overrides
|
||||||
|
# inlinevar-naming-style.
|
||||||
|
#inlinevar-rgx=
|
||||||
|
|
||||||
|
# Naming style matching correct method names.
|
||||||
|
method-naming-style=snake_case
|
||||||
|
|
||||||
|
# Regular expression matching correct method names. Overrides method-naming-
|
||||||
|
# style.
|
||||||
|
#method-rgx=
|
||||||
|
|
||||||
|
# Naming style matching correct module names.
|
||||||
|
module-naming-style=snake_case
|
||||||
|
|
||||||
|
# Regular expression matching correct module names. Overrides module-naming-
|
||||||
|
# style.
|
||||||
|
#module-rgx=
|
||||||
|
|
||||||
|
# Colon-delimited sets of names that determine each other's naming style when
|
||||||
|
# the name regexes allow several styles.
|
||||||
|
name-group=
|
||||||
|
|
||||||
|
# Regular expression which should only match function or class names that do
|
||||||
|
# not require a docstring.
|
||||||
|
no-docstring-rgx=^_
|
||||||
|
|
||||||
|
# List of decorators that produce properties, such as abc.abstractproperty. Add
|
||||||
|
# to this list to register other decorators that produce valid properties.
|
||||||
|
# These decorators are taken in consideration only for invalid-name.
|
||||||
|
property-classes=abc.abstractproperty
|
||||||
|
|
||||||
|
# Naming style matching correct variable names.
|
||||||
|
variable-naming-style=snake_case
|
||||||
|
|
||||||
|
# Regular expression matching correct variable names. Overrides variable-
|
||||||
|
# naming-style.
|
||||||
|
#variable-rgx=
|
||||||
|
|
||||||
|
|
||||||
|
[LOGGING]
|
||||||
|
|
||||||
|
# Format style used to check logging format string. `old` means using %
|
||||||
|
# formatting, `new` is for `{}` formatting,and `fstr` is for f-strings.
|
||||||
|
logging-format-style=old
|
||||||
|
|
||||||
|
# Logging modules to check that the string format arguments are in logging
|
||||||
|
# function parameter format.
|
||||||
|
logging-modules=logging
|
||||||
|
|
||||||
|
|
||||||
|
[TYPECHECK]
|
||||||
|
|
||||||
|
# List of decorators that produce context managers, such as
|
||||||
|
# contextlib.contextmanager. Add to this list to register other decorators that
|
||||||
|
# produce valid context managers.
|
||||||
|
contextmanager-decorators=contextlib.contextmanager
|
||||||
|
|
||||||
|
# List of members which are set dynamically and missed by pylint inference
|
||||||
|
# system, and so shouldn't trigger E1101 when accessed. Python regular
|
||||||
|
# expressions are accepted.
|
||||||
|
generated-members=
|
||||||
|
|
||||||
|
# Tells whether missing members accessed in mixin class should be ignored. A
|
||||||
|
# mixin class is detected if its name ends with "mixin" (case insensitive).
|
||||||
|
ignore-mixin-members=yes
|
||||||
|
|
||||||
|
# Tells whether to warn about missing members when the owner of the attribute
|
||||||
|
# is inferred to be None.
|
||||||
|
ignore-none=yes
|
||||||
|
|
||||||
|
# This flag controls whether pylint should warn about no-member and similar
|
||||||
|
# checks whenever an opaque object is returned when inferring. The inference
|
||||||
|
# can return multiple potential results while evaluating a Python object, but
|
||||||
|
# some branches might not be evaluated, which results in partial inference. In
|
||||||
|
# that case, it might be useful to still emit no-member and other checks for
|
||||||
|
# the rest of the inferred objects.
|
||||||
|
ignore-on-opaque-inference=yes
|
||||||
|
|
||||||
|
# List of class names for which member attributes should not be checked (useful
|
||||||
|
# for classes with dynamically set attributes). This supports the use of
|
||||||
|
# qualified names.
|
||||||
|
ignored-classes=optparse.Values,thread._local,_thread._local
|
||||||
|
|
||||||
|
# List of module names for which member attributes should not be checked
|
||||||
|
# (useful for modules/projects where namespaces are manipulated during runtime
|
||||||
|
# and thus existing member attributes cannot be deduced by static analysis). It
|
||||||
|
# supports qualified module names, as well as Unix pattern matching.
|
||||||
|
ignored-modules=
|
||||||
|
|
||||||
|
# Show a hint with possible names when a member name was not found. The aspect
|
||||||
|
# of finding the hint is based on edit distance.
|
||||||
|
missing-member-hint=yes
|
||||||
|
|
||||||
|
# The minimum edit distance a name should have in order to be considered a
|
||||||
|
# similar match for a missing member name.
|
||||||
|
missing-member-hint-distance=1
|
||||||
|
|
||||||
|
# The total number of similar names that should be taken in consideration when
|
||||||
|
# showing a hint for a missing member.
|
||||||
|
missing-member-max-choices=1
|
||||||
|
|
||||||
|
# List of decorators that change the signature of a decorated function.
|
||||||
|
signature-mutators=
|
||||||
|
|
||||||
|
|
||||||
|
[SIMILARITIES]
|
||||||
|
|
||||||
|
# Ignore comments when computing similarities.
|
||||||
|
ignore-comments=yes
|
||||||
|
|
||||||
|
# Ignore docstrings when computing similarities.
|
||||||
|
ignore-docstrings=yes
|
||||||
|
|
||||||
|
# Ignore imports when computing similarities.
|
||||||
|
ignore-imports=no
|
||||||
|
|
||||||
|
# Minimum lines number of a similarity.
|
||||||
|
min-similarity-lines=4
|
||||||
|
|
||||||
|
|
||||||
|
[STRING]
|
||||||
|
|
||||||
|
# This flag controls whether the implicit-str-concat-in-sequence should
|
||||||
|
# generate a warning on implicit string concatenation in sequences defined over
|
||||||
|
# several lines.
|
||||||
|
check-str-concat-over-line-jumps=no
|
||||||
|
|
||||||
|
|
||||||
|
[VARIABLES]
|
||||||
|
|
||||||
|
# List of additional names supposed to be defined in builtins. Remember that
|
||||||
|
# you should avoid defining new builtins when possible.
|
||||||
|
additional-builtins=
|
||||||
|
|
||||||
|
# Tells whether unused global variables should be treated as a violation.
|
||||||
|
allow-global-unused-variables=yes
|
||||||
|
|
||||||
|
# List of strings which can identify a callback function by name. A callback
|
||||||
|
# name must start or end with one of those strings.
|
||||||
|
callbacks=cb_,
|
||||||
|
_cb
|
||||||
|
|
||||||
|
# A regular expression matching the name of dummy variables (i.e. expected to
|
||||||
|
# not be used).
|
||||||
|
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
|
||||||
|
|
||||||
|
# Argument names that match this expression will be ignored. Default to name
|
||||||
|
# with leading underscore.
|
||||||
|
ignored-argument-names=_.*|^ignored_|^unused_
|
||||||
|
|
||||||
|
# Tells whether we should check for unused import in __init__ files.
|
||||||
|
init-import=no
|
||||||
|
|
||||||
|
# List of qualified module names which can have objects that can redefine
|
||||||
|
# builtins.
|
||||||
|
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
|
||||||
|
|
||||||
|
|
||||||
|
[FORMAT]
|
||||||
|
|
||||||
|
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
|
||||||
|
expected-line-ending-format=
|
||||||
|
|
||||||
|
# Regexp for a line that is allowed to be longer than the limit.
|
||||||
|
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
|
||||||
|
|
||||||
|
# Number of spaces of indent required inside a hanging or continued line.
|
||||||
|
indent-after-paren=4
|
||||||
|
|
||||||
|
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
||||||
|
# tab).
|
||||||
|
indent-string=' '
|
||||||
|
|
||||||
|
# Maximum number of characters on a single line.
|
||||||
|
max-line-length=90
|
||||||
|
|
||||||
|
# Maximum number of lines in a module.
|
||||||
|
max-module-lines=1000
|
||||||
|
|
||||||
|
# List of optional constructs for which whitespace checking is disabled. `dict-
|
||||||
|
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
|
||||||
|
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
|
||||||
|
# `empty-line` allows space-only lines.
|
||||||
|
no-space-check=trailing-comma,
|
||||||
|
dict-separator
|
||||||
|
|
||||||
|
# Allow the body of a class to be on the same line as the declaration if body
|
||||||
|
# contains single statement.
|
||||||
|
single-line-class-stmt=no
|
||||||
|
|
||||||
|
# Allow the body of an if to be on the same line as the test if there is no
|
||||||
|
# else.
|
||||||
|
single-line-if-stmt=no
|
||||||
|
|
||||||
|
|
||||||
|
[MISCELLANEOUS]
|
||||||
|
|
||||||
|
# List of note tags to take in consideration, separated by a comma.
|
||||||
|
notes=FIXME,
|
||||||
|
XXX,
|
||||||
|
TODO
|
||||||
|
|
||||||
|
|
||||||
|
[SPELLING]
|
||||||
|
|
||||||
|
# Limits count of emitted suggestions for spelling mistakes.
|
||||||
|
max-spelling-suggestions=4
|
||||||
|
|
||||||
|
# Spelling dictionary name. Available dictionaries: none. To make it work,
|
||||||
|
# install the python-enchant package.
|
||||||
|
spelling-dict=
|
||||||
|
|
||||||
|
# List of comma separated words that should not be checked.
|
||||||
|
spelling-ignore-words=
|
||||||
|
|
||||||
|
# A path to a file that contains the private dictionary; one word per line.
|
||||||
|
spelling-private-dict-file=
|
||||||
|
|
||||||
|
# Tells whether to store unknown words to the private dictionary (see the
|
||||||
|
# --spelling-private-dict-file option) instead of raising a message.
|
||||||
|
spelling-store-unknown-words=no
|
||||||
|
|
||||||
|
|
||||||
|
[CLASSES]
|
||||||
|
|
||||||
|
# List of method names used to declare (i.e. assign) instance attributes.
|
||||||
|
defining-attr-methods=__init__,
|
||||||
|
__new__,
|
||||||
|
setUp,
|
||||||
|
__post_init__
|
||||||
|
|
||||||
|
# List of member names, which should be excluded from the protected access
|
||||||
|
# warning.
|
||||||
|
exclude-protected=_asdict,
|
||||||
|
_fields,
|
||||||
|
_replace,
|
||||||
|
_source,
|
||||||
|
_make
|
||||||
|
|
||||||
|
# List of valid names for the first argument in a class method.
|
||||||
|
valid-classmethod-first-arg=cls
|
||||||
|
|
||||||
|
# List of valid names for the first argument in a metaclass class method.
|
||||||
|
valid-metaclass-classmethod-first-arg=cls
|
||||||
|
|
||||||
|
|
||||||
|
[DESIGN]
|
||||||
|
|
||||||
|
# Maximum number of arguments for function / method.
|
||||||
|
max-args=10
|
||||||
|
|
||||||
|
# Maximum number of attributes for a class (see R0902).
|
||||||
|
max-attributes=20
|
||||||
|
|
||||||
|
# Maximum number of boolean expressions in an if statement (see R0916).
|
||||||
|
max-bool-expr=5
|
||||||
|
|
||||||
|
# Maximum number of branch for function / method body.
|
||||||
|
max-branches=12
|
||||||
|
|
||||||
|
# Maximum number of locals for function / method body.
|
||||||
|
max-locals=15
|
||||||
|
|
||||||
|
# Maximum number of parents for a class (see R0901).
|
||||||
|
max-parents=7
|
||||||
|
|
||||||
|
# Maximum number of public methods for a class (see R0904).
|
||||||
|
max-public-methods=20
|
||||||
|
|
||||||
|
# Maximum number of return / yield for function / method body.
|
||||||
|
max-returns=6
|
||||||
|
|
||||||
|
# Maximum number of statements in function / method body.
|
||||||
|
max-statements=50
|
||||||
|
|
||||||
|
# Minimum number of public methods for a class (see R0903).
|
||||||
|
min-public-methods=2
|
||||||
|
|
||||||
|
|
||||||
|
[IMPORTS]
|
||||||
|
|
||||||
|
# List of modules that can be imported at any level, not just the top level
|
||||||
|
# one.
|
||||||
|
allow-any-import-level=
|
||||||
|
|
||||||
|
# Allow wildcard imports from modules that define __all__.
|
||||||
|
allow-wildcard-with-all=no
|
||||||
|
|
||||||
|
# Analyse import fallback blocks. This can be used to support both Python 2 and
|
||||||
|
# 3 compatible code, which means that the block might have code that exists
|
||||||
|
# only in one or another interpreter, leading to false positives when analysed.
|
||||||
|
analyse-fallback-blocks=no
|
||||||
|
|
||||||
|
# Deprecated modules which should not be used, separated by a comma.
|
||||||
|
deprecated-modules=optparse,tkinter.tix
|
||||||
|
|
||||||
|
# Create a graph of external dependencies in the given file (report RP0402 must
|
||||||
|
# not be disabled).
|
||||||
|
ext-import-graph=
|
||||||
|
|
||||||
|
# Create a graph of every (i.e. internal and external) dependencies in the
|
||||||
|
# given file (report RP0402 must not be disabled).
|
||||||
|
import-graph=
|
||||||
|
|
||||||
|
# Create a graph of internal dependencies in the given file (report RP0402 must
|
||||||
|
# not be disabled).
|
||||||
|
int-import-graph=
|
||||||
|
|
||||||
|
# Force import order to recognize a module as part of the standard
|
||||||
|
# compatibility libraries.
|
||||||
|
known-standard-library=
|
||||||
|
|
||||||
|
# Force import order to recognize a module as part of a third party library.
|
||||||
|
known-third-party=enchant
|
||||||
|
|
||||||
|
# Couples of modules and preferred modules, separated by a comma.
|
||||||
|
preferred-modules=
|
||||||
|
|
||||||
|
|
||||||
|
[EXCEPTIONS]
|
||||||
|
|
||||||
|
# Exceptions that will emit a warning when being caught. Defaults to
|
||||||
|
# "BaseException, Exception".
|
||||||
|
overgeneral-exceptions=BaseException,
|
||||||
|
Exception
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Required
|
||||||
|
version: 2
|
||||||
|
build:
|
||||||
|
os: "ubuntu-22.04"
|
||||||
|
tools:
|
||||||
|
python: "3.8"
|
||||||
|
|
||||||
|
# Build documentation in the docs/ directory with Sphinx
|
||||||
|
sphinx:
|
||||||
|
configuration: docs/code-docs/source/conf.py
|
||||||
|
fail_on_warning: false
|
||||||
|
|
||||||
|
# Optionally build your docs in additional formats such as PDF
|
||||||
|
formats:
|
||||||
|
- pdf
|
||||||
|
|
||||||
|
# Optionally set the version of Python and requirements required to build your docs
|
||||||
|
python:
|
||||||
|
install:
|
||||||
|
- requirements: requirements/requirements-readthedocs.txt
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
[style]
|
||||||
|
SPLIT_ALL_COMMA_SEPARATED_VALUES = false
|
||||||
|
COLUMN_LIMIT = 119
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<!-- This file is duplicated as CLAUDE.md and AGENTS.md. Keep them in sync. -->
|
||||||
|
# AGENTS.md — Workspace-level instructions for AI coding agents
|
||||||
|
|
||||||
|
## DeepSpeed Project Rules
|
||||||
|
|
||||||
|
### Commit & CI requirements
|
||||||
|
|
||||||
|
- All commits MUST have a `Signed-off-by` line (use `--signoff`). Get the name and email from `git config user.name` / `git config user.email`.
|
||||||
|
- Formatting: yapf (column_limit=119, `.style.yapf`) + flake8 (`.flake8`).
|
||||||
|
- Always verify changed files pass pre-commit checks before committing: `pre-commit run --files <changed_files>`. Only check modified files, not the entire codebase. Config: `.pre-commit-config.yaml`.
|
||||||
|
- `check-torchdist` hook: NEVER directly import torch's distributed module. Use `import deepspeed.comm as dist` instead.
|
||||||
|
- New files require license header:
|
||||||
|
```
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
# DeepSpeed Team
|
||||||
|
```
|
||||||
|
|
||||||
|
### Code change discipline
|
||||||
|
|
||||||
|
- NEVER make cosmetic/formatting-only changes to existing code. Only add/modify lines that are functionally necessary. Minimizing diff noise is critical for code review.
|
||||||
|
- Delete dead code decisively — if code is unused at runtime (only referenced in tests), remove it along with its tests.
|
||||||
|
- Prefer consolidating tests over proliferating test files.
|
||||||
|
- Blend in: when modifying code, read the surrounding context and match the style of neighboring code (naming, spacing, patterns, idioms).
|
||||||
|
- Write beginner-friendly code: avoid deeply nested expressions or chained logic. Break complex expressions into clear, named intermediate steps.
|
||||||
|
- Comments should explain **why**, not **what**. Describe the purpose and reasoning, not the mechanics that the code already shows.
|
||||||
|
- New features must include corresponding tests and documentation updates.
|
||||||
|
|
||||||
|
## Tool Caveats
|
||||||
|
|
||||||
|
### Edit tool auto-formatter
|
||||||
|
|
||||||
|
The Edit tool has a hidden auto-formatter that silently changes quotes, whitespace, blank lines, and line wrapping. For format-sensitive modifications (e.g., when exact formatting matters for pre-commit), use `bash` with `sed`, `python`, or `cat` instead.
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<!-- This file is duplicated as CLAUDE.md and AGENTS.md. Keep them in sync. -->
|
||||||
|
# AGENTS.md — Workspace-level instructions for AI coding agents
|
||||||
|
|
||||||
|
## DeepSpeed Project Rules
|
||||||
|
|
||||||
|
### Commit & CI requirements
|
||||||
|
|
||||||
|
- All commits MUST have a `Signed-off-by` line (use `--signoff`). Get the name and email from `git config user.name` / `git config user.email`.
|
||||||
|
- Formatting: yapf (column_limit=119, `.style.yapf`) + flake8 (`.flake8`).
|
||||||
|
- Always verify changed files pass pre-commit checks before committing: `pre-commit run --files <changed_files>`. Only check modified files, not the entire codebase. Config: `.pre-commit-config.yaml`.
|
||||||
|
- `check-torchdist` hook: NEVER directly import torch's distributed module. Use `import deepspeed.comm as dist` instead.
|
||||||
|
- New files require license header:
|
||||||
|
```
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
# DeepSpeed Team
|
||||||
|
```
|
||||||
|
|
||||||
|
### Code change discipline
|
||||||
|
|
||||||
|
- NEVER make cosmetic/formatting-only changes to existing code. Only add/modify lines that are functionally necessary. Minimizing diff noise is critical for code review.
|
||||||
|
- Delete dead code decisively — if code is unused at runtime (only referenced in tests), remove it along with its tests.
|
||||||
|
- Prefer consolidating tests over proliferating test files.
|
||||||
|
- Blend in: when modifying code, read the surrounding context and match the style of neighboring code (naming, spacing, patterns, idioms).
|
||||||
|
- Write beginner-friendly code: avoid deeply nested expressions or chained logic. Break complex expressions into clear, named intermediate steps.
|
||||||
|
- Comments should explain **why**, not **what**. Describe the purpose and reasoning, not the mechanics that the code already shows.
|
||||||
|
- New features must include corresponding tests and documentation updates.
|
||||||
|
|
||||||
|
## Tool Caveats
|
||||||
|
|
||||||
|
### Edit tool auto-formatter
|
||||||
|
|
||||||
|
The Edit tool has a hidden auto-formatter that silently changes quotes, whitespace, blank lines, and line wrapping. For format-sensitive modifications (e.g., when exact formatting matters for pre-commit), use `bash` with `sed`, `python`, or `cat` instead.
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# This file is used to subscribe for notifications for PRs
|
||||||
|
# related to specific file paths, does not necessarily mean
|
||||||
|
# approval is required from these people before merging.
|
||||||
|
#
|
||||||
|
# Learn more about CODEOWNERS syntax here:
|
||||||
|
# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
|
||||||
|
|
||||||
|
|
||||||
|
# top-level repo folders
|
||||||
|
/.github/ @loadams
|
||||||
|
/azure/ @loadams
|
||||||
|
/benchmarks/ @guanhuawang @tjruwase
|
||||||
|
/bin/ @loadams
|
||||||
|
/csrc/ @tjruwase
|
||||||
|
/deepspeed/ @loadams @tjruwase
|
||||||
|
/docker/ @loadams @guanhuawang
|
||||||
|
/docs/ @loadams @tjruwase
|
||||||
|
/examples/ @jomayeri @tohtana
|
||||||
|
/op_builder/ @loadams @tjruwase @jomayeri
|
||||||
|
/release/ @loadams @jomayeri
|
||||||
|
/requirements/ @loadams
|
||||||
|
/scripts/ @loadams @tjruwase
|
||||||
|
/tests/ @tjruwase @loadams @tohtana
|
||||||
|
|
||||||
|
# deepspeed
|
||||||
|
/deepspeed/autotuning/ @loadams
|
||||||
|
/deepspeed/checkpoint/ @tjruwase
|
||||||
|
/deepspeed/comm/ @guanhuawang
|
||||||
|
/deepspeed/compression/ @tjruwase
|
||||||
|
/deepspeed/elasticity/ @tjruwase
|
||||||
|
/deepspeed/launcher/ @loadams
|
||||||
|
/deepspeed/module_inject/ @hwchen2017 @loadams
|
||||||
|
/deepspeed/moe/ @tohtana
|
||||||
|
/deepspeed/monitor/ @tjruwase
|
||||||
|
/deepspeed/nebula/ @tjruwase
|
||||||
|
/deepspeed/nvme/ @tjruwase @jomayeri
|
||||||
|
/deepspeed/ops/ @tohtana
|
||||||
|
/deepspeed/pipe/ @tohtana @loadams
|
||||||
|
/deepspeed/profiling/ @loadams
|
||||||
|
/deepspeed/sequence/ @tohtana
|
||||||
|
/deepspeed/utils/ @tjruwase @tohtana
|
||||||
|
|
||||||
|
# inference
|
||||||
|
/deepspeed/inference/ @hwchen2017 @tohtana
|
||||||
|
/deepspeed/model_implementations/@tohtana @loadams
|
||||||
|
|
||||||
|
# training
|
||||||
|
/deepspeed/runtime/ @tjruwase @tohtana
|
||||||
|
/deepspeed/runtime/activation_checkpointing/ @tjruwase
|
||||||
|
/deepspeed/runtime/checkpoint_engine/ @tjruwase
|
||||||
|
/deepspeed/runtime/comm/ @guanhuawang
|
||||||
|
/deepspeed/runtime/compression/ @tjruwase
|
||||||
|
/deepspeed/runtime/data_pipeline/ @tjruwase
|
||||||
|
/deepspeed/runtime/domino/ @guanhuawang @hwchen2017
|
||||||
|
/deepspeed/runtime/fp16/ @tjruwase @tohtana
|
||||||
|
/deepspeed/runtime/fp16/onebit/ @tjruwase
|
||||||
|
/deepspeed/runtime/pipe/ @loadams @tohtana
|
||||||
|
/deepspeed/runtime/swap_tensor/ @tjruwase @jomayeri
|
||||||
|
/deepspeed/runtime/zero/ @tjruwase @tohtana
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Microsoft Open Source Code of Conduct
|
||||||
|
|
||||||
|
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||||
|
|
||||||
|
Resources:
|
||||||
|
|
||||||
|
- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
|
||||||
|
- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
|
||||||
|
- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# DeepSpeed TSC Committers #
|
||||||
|
|
||||||
|
| Name | GitHub ID | Affiliation
|
||||||
|
|--- | ---- | --- |
|
||||||
|
| Olatunji Ruwase | [tjruwase](https://github.com/tjruwase) | SnowFlake |
|
||||||
|
| Logan Adams | [loadams](https://github.com/loadams) | Microsoft |
|
||||||
|
| Masahiro Tanaka | [tohtana](https://github.com/tohtana) | Anyscale |
|
||||||
|
| Jeff Rasley | [jeffra](https://github.com/jeffra) | SnowFlake |
|
||||||
|
| Minjia Zhang | [minjiazhang](https://github.com/minjiazhang) | UIUC |
|
||||||
|
| Ashwin Aji | [ashwinma](https://github.com/ashwinma) | AMD |
|
||||||
|
| Sam Foreman | [saforem2](https://github.com/saforem2) | Argonne National Laboratory |
|
||||||
|
| Zhipeng Wang | [PKUWZP](https://github.com/PKUWZP) | LinkedIn |
|
||||||
|
| Guokai Ma | [delock](https://github.com/delock) | Intel |
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
# Contributing
|
||||||
|
DeepSpeed welcomes your contributions!
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
DeepSpeed uses [pre-commit](https://pre-commit.com/) to ensure that formatting is
|
||||||
|
consistent across DeepSpeed. First, ensure that `pre-commit` is installed from either
|
||||||
|
installing DeepSpeed or `pip install pre-commit`. Next, the pre-commit hooks must be
|
||||||
|
installed once before commits can be made:
|
||||||
|
```bash
|
||||||
|
pre-commit install
|
||||||
|
```
|
||||||
|
|
||||||
|
Afterwards, our suite of formatting tests run automatically before each `git commit`. You
|
||||||
|
can also run these manually:
|
||||||
|
```bash
|
||||||
|
pre-commit run --files $(git diff --name-only master)
|
||||||
|
```
|
||||||
|
If a formatting test fails, it will fix the modified code in place and abort
|
||||||
|
the `git commit`. After looking over the changes, you can `git add <modified files>`
|
||||||
|
and then repeat the previous `git commit` command.
|
||||||
|
|
||||||
|
You can also run:
|
||||||
|
```
|
||||||
|
make format
|
||||||
|
```
|
||||||
|
which will do the same as above, and it'll also automatically build a `venv` python environment if you
|
||||||
|
don't already have one, which will isolate the requirements of this project from requirements of other projects.
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
DeepSpeed tracks two types of tests: unit tests and more costly model convergence tests.
|
||||||
|
The model convergence tests train
|
||||||
|
[DeepSpeedExamples](https://github.com/deepspeedai/DeepSpeedExamples/) and measure
|
||||||
|
end-to-end convergence and related metrics. Unit tests are found in `tests/unit/` and
|
||||||
|
the model convergence tests are found in `tests/model/`.
|
||||||
|
|
||||||
|
### Unit Tests
|
||||||
|
[PyTest](https://docs.pytest.org/en/latest/) is used to execute tests. PyTest can be
|
||||||
|
installed from PyPI via `pip install pytest`. Simply invoke `pytest --forked` to run the
|
||||||
|
unit tests:
|
||||||
|
```bash
|
||||||
|
pytest --forked tests/unit/
|
||||||
|
```
|
||||||
|
You can also provide the `-v` flag to `pytest` to see additional information about the
|
||||||
|
tests. Note that [pytest-forked](https://github.com/pytest-dev/pytest-forked) and the
|
||||||
|
`--forked` flag are required to test CUDA functionality in distributed tests. Using
|
||||||
|
`--forked` is safe because `import deepspeed` no longer initializes a CUDA context;
|
||||||
|
earlier versions probed CUDA at import time, which poisoned `fork()`.
|
||||||
|
|
||||||
|
You can also run:
|
||||||
|
```
|
||||||
|
make test
|
||||||
|
```
|
||||||
|
|
||||||
|
### Diff-based CI test selection
|
||||||
|
Some GPU CI workflows (currently `modal-torch-latest`, which runs `tests/unit/v1/`)
|
||||||
|
don't run the whole suite on every PR. Instead, `ci/tests_fetcher.py` looks at the
|
||||||
|
files your PR changes, builds an import graph over `deepspeed/` and the `unit` test
|
||||||
|
helpers, and runs only the tests that could be affected. This keeps CI fast without
|
||||||
|
losing coverage (`push` to `master` always runs everything). The full design — and
|
||||||
|
how to drive and extend it — is in
|
||||||
|
[`.github/workflows/TEST_SELECTION.md`](.github/workflows/TEST_SELECTION.md).
|
||||||
|
|
||||||
|
How it decides:
|
||||||
|
* It diffs your branch against the base branch's merge-base.
|
||||||
|
* Each changed Python file is traced *forward* to the tests that import it
|
||||||
|
(directly or transitively); those tests are selected.
|
||||||
|
* It **falls back to the full suite** (never to "no tests") whenever it can't
|
||||||
|
safely narrow: a missing base / merge-base, a changed shared fixture, build
|
||||||
|
system, CI script, or core runtime file, a deleted module that something still
|
||||||
|
imports, or any unexpected error in the selector itself.
|
||||||
|
|
||||||
|
Escape hatches:
|
||||||
|
* **Force the full suite for a push:** put `[test all]` (or `[no filter]`) anywhere
|
||||||
|
in a commit message on the branch.
|
||||||
|
* **Run all by touching infra:** changes to the run-all globs (CI config, build
|
||||||
|
system, `deepspeed/__init__.py`, collectives/accelerator, shared fixtures, etc.)
|
||||||
|
always trigger everything. See `COMMON_RUN_ALL_GLOBS` / `extra_run_all_globs` in
|
||||||
|
`ci/tests_fetcher.py`.
|
||||||
|
* **Runtime/dynamic deps the import graph can't see** (monkey-patching, plugin
|
||||||
|
registries, JIT ops, `deepspeed.initialize()`-time injection) are wired up via
|
||||||
|
the curated `DYNAMIC_EDGES` map in `ci/tests_fetcher.py` — add an entry there if
|
||||||
|
you find a gap.
|
||||||
|
|
||||||
|
Preview/debug locally (pure stdlib, no DeepSpeed install needed):
|
||||||
|
```bash
|
||||||
|
# What would CI run for your branch?
|
||||||
|
python ci/tests_fetcher.py --base origin/master
|
||||||
|
cat ci/.test_selection/test_list.txt
|
||||||
|
|
||||||
|
# Why was a test (de)selected? Prints the import chains.
|
||||||
|
python ci/tests_fetcher.py --base origin/master --explain
|
||||||
|
```
|
||||||
|
|
||||||
|
> Note: under `pull_request_target` the `deploy` job runs the PR's `deepspeed/` and
|
||||||
|
> `tests/` but restores `ci/` from the base branch (the CI scripts hold the modal/HF
|
||||||
|
> secrets). So changes to `ci/*` only take effect once merged — validate them via a
|
||||||
|
> `pull_request`-triggered run or the `modal` CLI.
|
||||||
|
|
||||||
|
### Model Tests
|
||||||
|
To execute model tests, first [install DeepSpeed](#installation). The
|
||||||
|
[DeepSpeedExamples](https://github.com/deepspeedai/DeepSpeedExamples/) repository is cloned
|
||||||
|
as part of this process. Next, execute the model test driver:
|
||||||
|
```bash
|
||||||
|
cd tests/model/
|
||||||
|
pytest run_sanity_check.py
|
||||||
|
```
|
||||||
|
Note that the `--forked` flag is not necessary for the model tests.
|
||||||
|
|
||||||
|
## Developer Certificate of Origin
|
||||||
|
This project welcomes contributions and suggestions. All contributions to deepspeedai projects
|
||||||
|
require commits to be signed off with a [Developer Certificate of Origin](https://en.wikipedia.org/wiki/Developer_Certificate_of_Origin)
|
||||||
|
(DCO) declaring that you have the right to, and actually do, grant us the rights to use your contribution.
|
||||||
|
|
||||||
|
When you submit a pull request, the DCO app will check for the presence of signed commits.
|
||||||
|
Information about how this check works is here: https://github.com/dcoapp/app?tab=readme-ov-file#how-it-works
|
||||||
|
|
||||||
|
To sign commits, you will need to include `-s` when running `git commit`. For example, `git commit -s -m "Commit message"`. One note, creating PRs via the GitHub interface do not appear to include this option. If you forget this, clicking on the failing check in your PR will point you to commands you can run to rebase and sign previous commits.
|
||||||
|
|
||||||
|
## Code of Conduct
|
||||||
|
This project has adopted the [Microsoft Open Source Code of
|
||||||
|
Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the
|
||||||
|
[Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact
|
||||||
|
[opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or
|
||||||
|
comments.
|
||||||
|
|
||||||
|
## New Feature Contribution Guidelines
|
||||||
|
Unlike bug fix or improving existing feature (where users usually directly submit a PR and we review it), adding a new feature to DeepSpeed requires several steps: (1) proposal and discussion, (2) implementation and verification, (3) release and maintenance. This general guideline applies to all new feature contributions. Core DeepSpeed team member contributions may complete step 1 internally.
|
||||||
|
|
||||||
|
### Step 1: proposal and discussion
|
||||||
|
We ask users to first post your intended feature in an issue. This issue needs to include:
|
||||||
|
|
||||||
|
* A description of the proposed feature.
|
||||||
|
* A motivation of why it will be useful to DeepSpeed users.
|
||||||
|
* A rough design of how you implement the feature inside DeepSpeed.
|
||||||
|
* (Important) Results or planned experiments to demonstrate the effectiveness and correctness of the feature.
|
||||||
|
* If this is a general feature applicable to different tasks, we require testing it on at least one CV task (e.g., [CIFAR](https://www.deepspeed.ai/tutorials/cifar-10/)) and one NLP task (e.g., [SQuAD](https://www.deepspeed.ai/tutorials/bert-finetuning/)). If this is a feature for one kind of task only, it is fine to just test on the specific task.
|
||||||
|
* If the feature only affects performance and does not affect training convergence, we require testing on a fraction of training to demonstrate that the training/validation loss are consistent with baseline, and that the performance is better than baseline.
|
||||||
|
* If the feature does affect training convergence, we require testing the whole training to demonstrate that the feature achieves better/on-par final model quality and training performance compared to baseline.
|
||||||
|
|
||||||
|
Based on the issue we shall discuss the merit of the new feature and decide whether accept or decline the proposal. Once accepted and after we confirm the design and implementation plan, we are ready for step 2.
|
||||||
|
|
||||||
|
### Step 2: implementation and verification
|
||||||
|
Contributor will go ahead and implement the feature, and the DeepSpeed team will provide guidance/helps as needed. The required deliverables include:
|
||||||
|
|
||||||
|
* A PR to [deepspeedai/DeepSpeed](https://github.com/deepspeedai/DeepSpeed) including (1) the feature implementation (2) unit tests (3) documentation (4) tutorial
|
||||||
|
* A PR to [deepspeedai/DeepSpeedExamples](https://github.com/deepspeedai/DeepSpeedExamples) or [deepspeedai/Megatron-DeepSpeed](https://github.com/deepspeedai/Megatron-DeepSpeed) including the examples of how to use the feature (this is related to the planned testing experiments in proposal)
|
||||||
|
* In the implementation (code, documentation, tutorial), we require the feature author to record their GitHub username as a contact method for future questions/maintenance.
|
||||||
|
|
||||||
|
After receiving the PRs, we will review them and merge them after necessary tests/fixes.
|
||||||
|
|
||||||
|
### Step 3: release and maintenance
|
||||||
|
After the PRs are merged, we will announce the feature on our website (with credit to the feature author). We ask the feature author to commit to the maintenance of the feature.
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
|
||||||
|
# DeepSpeed Project Charter and Governance
|
||||||
|
|
||||||
|
This charter sets forth the responsibilities and procedures for technical contribution to, and oversight of, the DeepSpeed open source project. All contributors (including committers, maintainers, and other technical positions) and other participants in the Project (collectively, "Collaborators") must comply with the terms of this Charter.
|
||||||
|
|
||||||
|
## Mission and Scope of the Project
|
||||||
|
|
||||||
|
The mission of the Project is to DeepSpeed is a deep learning optimization library that makes distributed training and inference easy, efficient, and effective.
|
||||||
|
|
||||||
|
The scope of the Project includes collaborative development under the Project License (as defined herein) supporting the mission, including documentation, testing, integration, and the creation of other artifacts that aid the development, deployment, operation, or adoption of the open source project.
|
||||||
|
|
||||||
|
## Technical Steering Committee
|
||||||
|
|
||||||
|
1. The Technical Steering Committee (the "TSC") will be responsible for all technical oversight of the open source Project.
|
||||||
|
|
||||||
|
2. The TSC voting members are initially the Project's Committers. At the inception of the project, the Committers of the Project will be as set forth within the "CONTRIBUTING" file within the Project's code repository. The TSC may choose an alternative approach for determining the voting members of the TSC, and any such alternative approach will be documented in the CONTRIBUTING file. Any meetings of the Technical Steering Committee are intended to be open to the public, and can be conducted electronically, via teleconference, or in person.
|
||||||
|
|
||||||
|
3. TSC projects generally will involve Contributors and Committers. The TSC may adopt or modify roles so long as the roles are documented in the CONTRIBUTING file. Unless otherwise documented:
|
||||||
|
|
||||||
|
- **Contributors** include anyone in the technical community that contributes code, documentation, or other technical artifacts to the Project.
|
||||||
|
- **Committers** are Contributors who have earned the ability to modify ("commit") source code, documentation, or other technical artifacts in a project's repository.
|
||||||
|
|
||||||
|
- A Contributor may become a Committer by a majority approval of the existing Committers. A Committer may be removed by a majority approval of the other existing Committers.
|
||||||
|
|
||||||
|
4. Participation in the Project through becoming a Contributor and Committer is open to anyone so long as they abide by the terms of this Charter.
|
||||||
|
|
||||||
|
5. The TSC may:
|
||||||
|
- Establish workflow procedures for the submission, approval, and closure/archiving of projects.
|
||||||
|
- Set requirements for the promotion of Contributors to Committer status, as applicable.
|
||||||
|
- Amend, adjust, refine and/or eliminate the roles of Contributors and Committers, and create new roles, and publicly document any TSC roles, as it sees fit.
|
||||||
|
|
||||||
|
6. The TSC may elect a TSC Chair, who will preside over meetings of the TSC and will serve until their resignation or replacement by the TSC. The TSC Chair, or any other TSC member so designated by the TSC, will serve as the primary communication contact between the Project and AI & Data, a directed fund of The Linux Foundation.
|
||||||
|
|
||||||
|
7. Responsibilities: The TSC will be responsible for all aspects of oversight relating to the Project, which may include:
|
||||||
|
|
||||||
|
- Coordinating the technical direction of the Project.
|
||||||
|
- Approving project or system proposals (including, but not limited to, incubation, deprecation, and changes to a sub-project's scope).
|
||||||
|
- Organizing sub-projects and removing sub-projects.
|
||||||
|
- Creating sub-committees or working groups to focus on cross-project technical issues and requirements.
|
||||||
|
- Appointing representatives to work with other open source or open standards communities.
|
||||||
|
- Establishing community norms, workflows, issuing releases, and security issue reporting policies.
|
||||||
|
- Approving and implementing policies and processes for contributing (to be published in the CONTRIBUTING file) and coordinating with the series manager of the Project (as provided for in the Series Agreement, the "Series Manager") to resolve matters or concerns that may arise as set forth in Section 7 of this Charter.
|
||||||
|
- Discussions, seeking consensus, and where necessary, voting on technical matters relating to the code base that affect multiple projects.
|
||||||
|
- Coordinating any marketing, events, or communications regarding the Project.
|
||||||
|
|
||||||
|
## TSC Voting
|
||||||
|
|
||||||
|
1. While the Project aims to operate as a consensus-based community, if any TSC decision requires a vote to move the Project forward, the voting members of the TSC will vote on a one vote per voting member basis.
|
||||||
|
|
||||||
|
2. Quorum for TSC meetings requires at least fifty percent of all voting members of the TSC to be present. The TSC may continue to meet if quorum is not met but will be prevented from making any decisions at the meeting.
|
||||||
|
|
||||||
|
3. Except as provided in Section 7.c. and 8.a, decisions by vote at a meeting require a majority vote of those in attendance, provided quorum is met. Decisions made by electronic vote without a meeting require a majority vote of all voting members of the TSC.
|
||||||
|
|
||||||
|
4. In the event a vote cannot be resolved by the TSC, any voting member of the TSC may refer the matter to the Series Manager for assistance in reaching a resolution.
|
||||||
|
|
||||||
|
## Compliance with Policies
|
||||||
|
|
||||||
|
1. This Charter is subject to the Series Agreement for the Project and the Operating Agreement of LF Projects. Contributors will comply with the policies of LF Projects as may be adopted and amended by LF Projects, including, without limitation, the policies listed at https://lfprojects.org/policies/.
|
||||||
|
|
||||||
|
2. The TSC may adopt a code of conduct ("CoC") for the Project, which is subject to approval by the Series Manager. In the event that a Project-specific CoC has not been approved, the LF Projects Code of Conduct listed at https://lfprojects.org/policies will apply for all Collaborators in the Project.
|
||||||
|
|
||||||
|
3. When amending or adopting any policy applicable to the Project, LF Projects will publish such policy, as to be amended or adopted, on its website at least 30 days prior to such policy taking effect; provided, however, that in the case of any amendment of the Trademark Policy or Terms of Use of LF Projects, any such amendment is effective upon publication on LF Project's website.
|
||||||
|
|
||||||
|
4. All Collaborators must allow open participation from any individual or organization meeting the requirements for contributing under this Charter and any policies adopted for all Collaborators by the TSC, regardless of competitive interests. Put another way, the Project community must not seek to exclude any participant based on any criteria, requirement, or reason other than those that are reasonable and applied on a non-discriminatory basis to all Collaborators in the Project community.
|
||||||
|
|
||||||
|
5. The Project will operate in a transparent, open, collaborative, and ethical manner at all times. The output of all Project discussions, proposals, timelines, decisions, and status should be made open and easily visible to all. Any potential violations of this requirement should be reported immediately to the Series Manager.
|
||||||
|
|
||||||
|
## Community Assets
|
||||||
|
|
||||||
|
1. LF Projects will hold title to all trade or service marks used by the Project ("Project Trademarks"), whether based on common law or registered rights. Project Trademarks will be transferred and assigned to LF Projects to hold on behalf of the Project. Any use of any Project Trademarks by Collaborators in the Project will be in accordance with the license from LF Projects and inure to the benefit of LF Projects.
|
||||||
|
|
||||||
|
2. The Project will, as permitted and in accordance with such license from LF Projects, develop and own all Project GitHub and social media accounts, and domain name registrations created by the Project community.
|
||||||
|
|
||||||
|
3. Under no circumstances will LF Projects be expected or required to undertake any action on behalf of the Project that is inconsistent with the tax-exempt status or purpose, as applicable, of the Joint Development Foundation or LF Projects, LLC.
|
||||||
|
|
||||||
|
## General Rules and Operations
|
||||||
|
|
||||||
|
The Project will:
|
||||||
|
|
||||||
|
1. Engage in the work of the Project in a professional manner consistent with maintaining a cohesive community, while also maintaining the goodwill and esteem of LF Projects, Joint Development Foundation, and other partner organizations in the open source community.
|
||||||
|
2. Respect the rights of all trademark owners, including any branding and trademark usage guidelines.
|
||||||
|
|
||||||
|
## Intellectual Property Policy
|
||||||
|
|
||||||
|
1. Collaborators acknowledge that the copyright in all new contributions will be retained by the copyright holder as independent works of authorship and that no contributor or copyright holder will be required to assign copyrights to the Project.
|
||||||
|
|
||||||
|
2. Except as described in Section 7.c., all contributions to the Project are subject to the following:
|
||||||
|
|
||||||
|
- All new inbound code contributions to the Project must be made using Apache License, Version 2.0 available at http://www.apache.org/licenses/LICENSE-2.0 (the "Project License").
|
||||||
|
- All new inbound code contributions must also be accompanied by a Developer Certificate of Origin (http://developercertificate.org) sign-off in the source code system that is submitted through a TSC-approved contribution process which will bind the authorized contributor and, if not self-employed, their employer to the applicable license.
|
||||||
|
- All outbound code will be made available under the Project License.
|
||||||
|
- Documentation will be received and made available by the Project under the Creative Commons Attribution 4.0 International License (available at http://creativecommons.org/licenses/by/4.0/).
|
||||||
|
- The Project may seek to integrate and contribute back to other open source projects ("Upstream Projects"). In such cases, the Project will conform to all license requirements of the Upstream Projects, including dependencies, leveraged by the Project. Upstream Project code contributions not stored within the Project's main code repository will comply with the contribution process and license terms for the applicable Upstream Project.
|
||||||
|
|
||||||
|
3. The TSC may approve the use of an alternative license or licenses for inbound or outbound contributions on an exception basis. To request an exception, please describe the contribution, the alternative open source license(s), and the justification for using an alternative open source license for the Project. License exceptions must be approved by a two-thirds vote of the entire TSC.
|
||||||
|
|
||||||
|
4. Contributed files should contain license information, such as SPDX short form identifiers, indicating the open source license or licenses pertaining to the file.
|
||||||
|
|
||||||
|
## Amendments
|
||||||
|
|
||||||
|
1. This charter may be amended by a two-thirds vote of the entire TSC and is subject to approval by LF Projects.
|
||||||
@@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
include *.txt README.md
|
||||||
|
include deepspeed/inference/v2/kernels/ragged_ops/libs/*.so
|
||||||
|
include deepspeed/inference/v2/kernels/cutlass_ops/libs/*.so
|
||||||
|
recursive-include requirements *.txt
|
||||||
|
recursive-include deepspeed *.cpp *.h *.hpp *.cu *.hip *.tr *.cuh *.cc *.json
|
||||||
|
recursive-include csrc *.cpp *.h *.hpp *.cu *.tr *.cuh *.cc
|
||||||
|
recursive-include op_builder *.py
|
||||||
|
recursive-include benchmarks *.py
|
||||||
|
recursive-include accelerator *.py
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
include *.txt README.md
|
||||||
|
recursive-include requirements *.txt
|
||||||
|
|
||||||
|
# this is for Windows only
|
||||||
|
recursive-include deepspeed *.tr
|
||||||
|
recursive-exclude deepspeed/ops/csrc *.cpp *.h *.cu *.cuh *.cc
|
||||||
|
prune csrc
|
||||||
|
prune op_builder
|
||||||
|
prune accelerator
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# usage: make help
|
||||||
|
|
||||||
|
.PHONY: help test format
|
||||||
|
.DEFAULT_GOAL := help
|
||||||
|
|
||||||
|
help: ## this help
|
||||||
|
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[0-9a-zA-Z_-]+:.*?##/ { printf " \033[36m%-22s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
|
||||||
|
echo $(MAKEFILE_LIST)
|
||||||
|
|
||||||
|
test: ## run tests
|
||||||
|
pytest --forked tests/unit/
|
||||||
|
|
||||||
|
format: ## fix formatting
|
||||||
|
@if [ ! -d "venv" ]; then \
|
||||||
|
python -m venv venv; \
|
||||||
|
. venv/bin/activate; \
|
||||||
|
pip install pre-commit -U; \
|
||||||
|
pre-commit clean; \
|
||||||
|
pre-commit uninstall; \
|
||||||
|
pre-commit install; \
|
||||||
|
deactivate; \
|
||||||
|
fi
|
||||||
|
. venv/bin/activate && pre-commit run --files $$(git diff --name-only master) && deactivate
|
||||||
@@ -0,0 +1,275 @@
|
|||||||
|
[](https://github.com/deepspeedai/DeepSpeed/blob/master/LICENSE)
|
||||||
|
[](https://pypi.org/project/deepspeed/)
|
||||||
|
[](https://pepy.tech/project/deepspeed)
|
||||||
|
[](#build-pipeline-status)
|
||||||
|
[](https://www.bestpractices.dev/projects/9530)
|
||||||
|
[](https://twitter.com/intent/follow?screen_name=DeepSpeedAI)
|
||||||
|
[](https://twitter.com/DeepSpeedAI_JP)
|
||||||
|
[](https://www.zhihu.com/people/deepspeed)
|
||||||
|
[](https://join.slack.com/t/deepspeedworkspace/shared_invite/zt-3a8pjd8dd-PCj2hMvR4Y2syPwVnjEoww)
|
||||||
|
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<img src="docs/assets/images/DeepSpeed_light.svg#gh-light-mode-only" width="400px">
|
||||||
|
<img src="docs/assets/images/DeepSpeed_dark_transparent.svg#gh-dark-mode-only" width="400px">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
## Office Hours
|
||||||
|
|
||||||
|
DeepSpeed hosts regular office hours on the last Tuesday of each month at 12:00 America/New_York to discuss development plans, features, etc. This meeting is public for anyone to join and ask questions.
|
||||||
|
The meeting is hosted on Zoom and can be joined [here](https://zoom-lfx.platform.linuxfoundation.org/meeting/93902569995?password=7d9c4fc9-3efa-4715-88f0-df8a6deb008b).
|
||||||
|
|
||||||
|
## Latest News
|
||||||
|
|
||||||
|
* [2026/05] [Using Muon Optimizer with DeepSpeed](https://github.com/deepspeedai/DeepSpeed/blob/master/blogs/muon-optimizer/README.md)
|
||||||
|
|
||||||
|
* [2026/05] [System DMA (SDMA) for ZeRO-3: offload collectives off compute units on AMD GPUs for better overlap](https://github.com/deepspeedai/DeepSpeed/blob/master/examples/sdma_allgather/README.md)
|
||||||
|
|
||||||
|
* [2026/03] DeepSpeed Team gave a tutorial at ASPLOS 2026 titled ["Building Efficient Large-Scale Model Systems with DeepSpeed: From Open-Source Foundations to Emerging Research" ](https://supercomputing-system-ai-lab.github.io/events/asplos2026-llm-tutorial/index.html)
|
||||||
|
|
||||||
|
* [2026/03] [Our SuperOffload work received an Honorable Mention for the ASPLOS 2026 Best Paper Award](https://dl.acm.org/doi/10.1145/3760250.3762217)
|
||||||
|
|
||||||
|
* [2025/12] [DeepSpeed Core API updates: PyTorch-style backward and low-precision master states](https://github.com/deepspeedai/DeepSpeed/blob/master/blogs/core_api_update/README.md)
|
||||||
|
|
||||||
|
* [2025/11] [DeepSpeed ZeRO++ powers large-scale distillation training of LLMs for Recommendation Systems at LinkedIn](https://aclanthology.org/2025.emnlp-industry.119/)
|
||||||
|
|
||||||
|
* [2025/10] We hosted the [Ray x DeepSpeed Meetup](https://luma.com/3wctqteh) at Anyscale. We shared our most recent work on SuperOffload, ZenFlow, Muon Optimizer Support, Arctic Long Sequence Training and DeepCompile. Please find the meetup slides [here](https://docs.google.com/presentation/d/1eM3mY6oW9GYkRy1Xz0iOnbbEr5T1t0JJXOM5BKtR-Ks/edit?slide=id.g38615d6b4c2_0_87#slide=id.g38615d6b4c2_0_87).
|
||||||
|
|
||||||
|
* [2025/10] [SuperOffload: Unleashing the Power of Large-Scale LLM Training on Superchips](https://pytorch.org/blog/superoffload-unleashing-the-power-of-large-scale-llm-training-on-superchips/)
|
||||||
|
|
||||||
|
* [2025/10] [Study of ZenFlow and ZeRO offload performance with DeepSpeed CPU core binding](https://github.com/deepspeedai/DeepSpeed/blob/master/blogs/zenflow-corebinding/README.md)
|
||||||
|
|
||||||
|
* [2025/08] [ZenFlow: Stall-Free Offloading Engine for LLM Training](https://pytorch.org/blog/zenflow-stall-free-offloading-engine-for-llm-training/)
|
||||||
|
|
||||||
|
* [2025/06] [Arctic Long Sequence Training (ALST) with DeepSpeed: Scalable And Efficient Training For Multi-Million Token Sequences](https://www.snowflake.com/en/engineering-blog/arctic-long-sequence-training-multi-million-token-ai/)
|
||||||
|
|
||||||
|
* [2025/06] [DeepNVMe: Affordable I/O scaling for Deep Learning Applications](https://github.com/deepspeedai/DeepSpeed/blob/master/blogs/deepnvme/06-2025/README.md)
|
||||||
|
|
||||||
|
|
||||||
|
<!-- NOTE: we must use html for news items otherwise links will be broken in the 'more news' section -->
|
||||||
|
<details>
|
||||||
|
<!-- NOTE: Maintain only three items in 'more news' section -->
|
||||||
|
<summary>More news</summary>
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li>[2025/04] <a href="https://github.com/deepspeedai/DeepSpeed/blob/master/blogs/deepcompile/README.md">DeepCompile: Unlocking Compiler Optimization for Distributed Training</a></li>
|
||||||
|
|
||||||
|
<li>[2025/03] <a href="https://github.com/deepspeedai/DeepSpeed/blob/master/blogs/huggingface-tp/README.md">DeepSpeed AutoTP: Automatic Tensor Parallel Training of Hugging Face models</a></li>
|
||||||
|
|
||||||
|
<li>[2024/12] <a href="https://github.com/deepspeedai/DeepSpeed/blob/master/blogs/ulysses-offload/README.md">Ulysses-Offload: Democratizing Long Context LLM Training</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Extreme Speed and Scale for DL Training
|
||||||
|
|
||||||
|
***[DeepSpeed](https://www.deepspeed.ai/) enabled the world's most powerful language models (at the time of this writing) such as [MT-530B](https://www.microsoft.com/en-us/research/blog/using-deepspeed-and-megatron-to-train-megatron-turing-nlg-530b-the-worlds-largest-and-most-powerful-generative-language-model/) and [BLOOM](https://huggingface.co/blog/bloom-megatron-deepspeed)***. DeepSpeed offers a confluence of [system innovations](https://www.deepspeed.ai/training/), that has made large scale DL training effective, and efficient, greatly improved ease of use, and redefined the DL training landscape in terms of scale that is possible. These innovations include ZeRO, ZeRO-Infinity, 3D-Parallelism, Ulysses Sequence Parallelism, DeepSpeed-MoE, etc.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# DeepSpeed Adoption
|
||||||
|
|
||||||
|
DeepSpeed was an important part of Microsoft’s
|
||||||
|
[AI at Scale](https://www.microsoft.com/en-us/research/project/ai-at-scale/)
|
||||||
|
initiative to enable next-generation AI capabilities at scale, where you can find more
|
||||||
|
information [here](https://innovation.microsoft.com/en-us/exploring-ai-at-scale).
|
||||||
|
|
||||||
|
DeepSpeed has been used to train many different large-scale models, below is a list of several examples that we are aware of (if you'd like to include your model please submit a PR):
|
||||||
|
|
||||||
|
* [Megatron-Turing NLG (530B)](https://www.microsoft.com/en-us/research/blog/using-deepspeed-and-megatron-to-train-megatron-turing-nlg-530b-the-worlds-largest-and-most-powerful-generative-language-model/)
|
||||||
|
* [Jurassic-1 (178B)](https://uploads-ssl.webflow.com/60fd4503684b466578c0d307/61138924626a6981ee09caf6_jurassic_tech_paper.pdf)
|
||||||
|
* [BLOOM (176B)](https://huggingface.co/blog/bloom-megatron-deepspeed)
|
||||||
|
* [GLM (130B)](https://github.com/THUDM/GLM-130B)
|
||||||
|
* [xTrimoPGLM (100B)](https://www.biorxiv.org/content/10.1101/2023.07.05.547496v2)
|
||||||
|
* [YaLM (100B)](https://github.com/yandex/YaLM-100B)
|
||||||
|
* [GPT-NeoX (20B)](https://github.com/EleutherAI/gpt-neox)
|
||||||
|
* [AlexaTM (20B)](https://www.amazon.science/blog/20b-parameter-alexa-model-sets-new-marks-in-few-shot-learning)
|
||||||
|
* [Turing NLG (17B)](https://www.microsoft.com/en-us/research/blog/turing-nlg-a-17-billion-parameter-language-model-by-microsoft/)
|
||||||
|
* [METRO-LM (5.4B)](https://arxiv.org/pdf/2204.06644.pdf)
|
||||||
|
|
||||||
|
DeepSpeed has been integrated with several different popular open-source DL frameworks such as:
|
||||||
|
|
||||||
|
| | Documentation |
|
||||||
|
| ---------------------------------------------------------------------------------------------- | -------------------------------------------- |
|
||||||
|
<img src="docs/assets/images/transformers-light.png#gh-light-mode-only" width="250px"><img src="docs/assets/images/transformers-dark.png#gh-dark-mode-only" width="250px"> | [Transformers with DeepSpeed](https://huggingface.co/docs/transformers/deepspeed) |
|
||||||
|
| <img src="docs/assets/images/accelerate-light.png#gh-light-mode-only" width="250px"><img src="docs/assets/images/accelerate-dark.png#gh-dark-mode-only" width="250px"> | [Accelerate with DeepSpeed](https://huggingface.co/docs/accelerate/usage_guides/deepspeed) |
|
||||||
|
| <img src="docs/assets/images/lightning-light.svg#gh-light-mode-only" width="200px"><img src="docs/assets/images/lightning-dark.svg#gh-dark-mode-only" width="200px"> | [Lightning with DeepSpeed](https://lightning.ai/docs/pytorch/stable/advanced/model_parallel.html#deepspeed) |
|
||||||
|
| <img src="docs/assets/images/mosaicml.svg" width="200px"> | [MosaicML with DeepSpeed](https://docs.mosaicml.com/projects/composer/en/latest/trainer/using_the_trainer.html?highlight=deepspeed#deepspeed-integration) |
|
||||||
|
| <img src="docs/assets/images/determined.svg" width="225px"> | [Determined with DeepSpeed](https://docs.determined.ai/latest/training/apis-howto/deepspeed/overview.html) |
|
||||||
|
| <img src="https://user-images.githubusercontent.com/58739961/187154444-fce76639-ac8d-429b-9354-c6fac64b7ef8.jpg" width=150> | [MMEngine with DeepSpeed](https://mmengine.readthedocs.io/en/latest/common_usage/large_model_training.html#deepspeed) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Build Pipeline Status
|
||||||
|
|
||||||
|
| Description | Status |
|
||||||
|
| ----------- | ------ |
|
||||||
|
| NVIDIA | [](https://github.com/deepspeedai/DeepSpeed/actions/workflows/nv-pre-compile-ops.yml) [](https://github.com/deepspeedai/DeepSpeed/actions/workflows/aws-torch-latest.yml) |
|
||||||
|
| AMD | [](https://github.com/deepspeedai/DeepSpeed/actions/workflows/amd-mi200.yml) |
|
||||||
|
| CPU | [](https://github.com/deepspeedai/DeepSpeed/actions/workflows/cpu-torch-latest.yml) |
|
||||||
|
| Intel Gaudi | [](https://github.com/deepspeedai/DeepSpeed/actions/workflows/hpu-gaudi2.yml) |
|
||||||
|
| Intel XPU | [](https://github.com/deepspeedai/DeepSpeed/actions/workflows/xpu-max1100.yml) |
|
||||||
|
| Integrations | [](https://github.com/deepspeedai/DeepSpeed/actions/workflows/aws-accelerate.yml) |
|
||||||
|
| Misc | [](https://github.com/deepspeedai/DeepSpeed/actions/workflows/formatting.yml) [](https://github.com/deepspeedai/DeepSpeed/actions/workflows/pages/pages-build-deployment) [](https://deepspeed.readthedocs.io/en/latest/?badge=latest)[](https://github.com/deepspeedai/DeepSpeed/actions/workflows/python.yml) |
|
||||||
|
| Huawei Ascend NPU | [](https://github.com/Ascend/Ascend-CI/actions/workflows/deepspeed.yaml) |
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
|
||||||
|
The quickest way to get started with DeepSpeed is via pip, this will install
|
||||||
|
the latest release of DeepSpeed which is not tied to specific PyTorch or CUDA
|
||||||
|
versions. DeepSpeed includes several C++/CUDA extensions that we commonly refer
|
||||||
|
to as our 'ops'. By default, all of these extensions/ops will be built
|
||||||
|
just-in-time (JIT) using [torch's JIT C++ extension loader that relies on
|
||||||
|
ninja](https://pytorch.org/docs/stable/cpp_extension.html) to build and
|
||||||
|
dynamically link them at runtime.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
* [PyTorch](https://pytorch.org/) must be installed _before_ installing DeepSpeed.
|
||||||
|
* For full feature support we recommend a version of PyTorch that is >= 2.0 and ideally the latest PyTorch stable release.
|
||||||
|
* A CUDA or ROCm compiler such as [nvcc](https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/#introduction) or [hipcc](https://github.com/ROCm-Developer-Tools/HIPCC) used to compile C++/CUDA/HIP extensions.
|
||||||
|
* Specific GPUs we develop and test against are listed below, this doesn't mean your GPU will not work if it doesn't fall into this category it's just DeepSpeed is most well tested on the following:
|
||||||
|
* NVIDIA: Pascal, Volta, Ampere, and Hopper architectures
|
||||||
|
* AMD: MI100 and MI200
|
||||||
|
|
||||||
|
## Contributed HW support
|
||||||
|
* DeepSpeed now support various HW accelerators.
|
||||||
|
|
||||||
|
| Contributor | Hardware | Accelerator Name | Contributor validated | Upstream validated |
|
||||||
|
|-------------|-------------------------------------|------------------| --------------------- |--------------------|
|
||||||
|
| Huawei | Huawei Ascend NPU | npu | Yes | No |
|
||||||
|
| Intel | Intel(R) Gaudi(R) 2 AI accelerator | hpu | Yes | Yes |
|
||||||
|
| Intel | Intel(R) Xeon(R) Processors | cpu | Yes | Yes |
|
||||||
|
| Intel | Intel(R) Data Center GPU Max series | xpu | Yes | Yes |
|
||||||
|
| Tecorigin | Scalable Data Analytics Accelerator | sdaa | Yes | No |
|
||||||
|
|
||||||
|
## PyPI
|
||||||
|
We regularly push releases to [PyPI](https://pypi.org/project/deepspeed/) and encourage users to install from there in most cases.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install deepspeed
|
||||||
|
```
|
||||||
|
|
||||||
|
After installation, you can validate your install and see which extensions/ops
|
||||||
|
your machine is compatible with via the DeepSpeed environment report.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ds_report
|
||||||
|
```
|
||||||
|
|
||||||
|
If you would like to pre-install any of the DeepSpeed extensions/ops (instead
|
||||||
|
of JIT compiling) or install pre-compiled ops via PyPI please see our [advanced
|
||||||
|
installation instructions](https://www.deepspeed.ai/tutorials/advanced-install/).
|
||||||
|
|
||||||
|
## Windows
|
||||||
|
Many DeepSpeed features are supported on Windows for both training and inference. You can read more about this in the original blog post [here](https://github.com/deepspeedai/DeepSpeed/tree/master/blogs/windows/08-2024/README.md). Among features that are currently not supported are async io (AIO) and GDS (which does not support Windows).
|
||||||
|
1. Install PyTorch, such as pytorch 2.3+cu121.
|
||||||
|
2. Install Visual C++ build tools, such as VS2022 C++ x64/x86 build tools.
|
||||||
|
3. Launch Cmd console with Administrator permissions for creating required symlink folders and ensure MSVC tools are added to your PATH or launch the Developer Command Prompt for Visual Studio 2022 with administrator permissions.
|
||||||
|
4. Run `build_win.bat` to build wheel in `dist` folder.
|
||||||
|
|
||||||
|
|
||||||
|
# Further Reading
|
||||||
|
|
||||||
|
All DeepSpeed documentation, tutorials, and blogs can be found on our website: [deepspeed.ai](https://www.deepspeed.ai/)
|
||||||
|
|
||||||
|
|
||||||
|
| | Description |
|
||||||
|
| ---------------------------------------------------------------------------------------------- | -------------------------------------------- |
|
||||||
|
| [Getting Started](https://www.deepspeed.ai/getting-started/) | First steps with DeepSpeed |
|
||||||
|
| [DeepSpeed JSON Configuration](https://www.deepspeed.ai/docs/config-json/) | Configuring DeepSpeed |
|
||||||
|
| [API Documentation](https://deepspeed.readthedocs.io/en/latest/) | Generated DeepSpeed API documentation |
|
||||||
|
| [Tutorials](https://www.deepspeed.ai/tutorials/) | Tutorials |
|
||||||
|
| [Blogs](https://www.deepspeed.ai/posts/) | Blogs |
|
||||||
|
|
||||||
|
|
||||||
|
# CI funding
|
||||||
|
|
||||||
|
This being an open source project we rely on others to provide us resources for CI hardware. At this moment Modal is kindly supporting our GPU CI runs by funding the hardware for us. Modal is an AI infrastructure platform for inference, fine-tuning, batch jobs and more. Get started with $30/mo in free credits today at https://modal.com. We have been getting an amazing support from Modal's team and will surely recommend them to your business.
|
||||||
|
|
||||||
|
# Contributing
|
||||||
|
DeepSpeed welcomes your contributions! Please see our
|
||||||
|
[contributing](CONTRIBUTING.md) guide for more details on formatting, testing,
|
||||||
|
etc.<br/>
|
||||||
|
Thanks so much to all of our amazing contributors!
|
||||||
|
|
||||||
|
<a href="https://github.com/deepspeedai/DeepSpeed/graphs/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=microsoft/DeepSpeed&r=" width="800px"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
## Developer Certificate of Origin
|
||||||
|
This project welcomes contributions and suggestions. Most contributions require you to
|
||||||
|
agree to a Developer Certificate of Origin [DCO](https://wiki.linuxfoundation.org/dco)
|
||||||
|
stating that they agree to the terms published at https://developercertificate.org for
|
||||||
|
that *particular* contribution.
|
||||||
|
|
||||||
|
DCOs are per-commit, so each commit needs to be signed off. These can be signed in
|
||||||
|
the commit by adding the `-s` flag. DCO enforcement can also be signed off in the PR
|
||||||
|
itself by clicking on the DCO enforcement check.
|
||||||
|
|
||||||
|
## Code of Conduct
|
||||||
|
This project has adopted the [Microsoft Open Source Code of
|
||||||
|
Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the
|
||||||
|
[Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact
|
||||||
|
[opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||||
|
|
||||||
|
# Publications
|
||||||
|
1. Samyam Rajbhandari, Jeff Rasley, Olatunji Ruwase, Yuxiong He. (2019) ZeRO: memory optimizations toward training trillion parameter models. [arXiv:1910.02054](https://arxiv.org/abs/1910.02054) and [In Proceedings of the International Conference for High Performance Computing, Networking, Storage and Analysis (SC '20)](https://dl.acm.org/doi/10.5555/3433701.3433727).
|
||||||
|
2. Jeff Rasley, Samyam Rajbhandari, Olatunji Ruwase, and Yuxiong He. (2020) DeepSpeed: System Optimizations Enable Training Deep Learning Models with Over 100 Billion Parameters. [In Proceedings of the 26th ACM SIGKDD International Conference on Knowledge Discovery & Data Mining (KDD '20, Tutorial)](https://dl.acm.org/doi/10.1145/3394486.3406703).
|
||||||
|
3. Minjia Zhang, Yuxiong He. (2020) Accelerating Training of Transformer-Based Language Models with Progressive Layer Dropping. [arXiv:2010.13369](https://arxiv.org/abs/2010.13369) and [NeurIPS 2020](https://proceedings.neurips.cc/paper/2020/hash/a1140a3d0df1c81e24ae954d935e8926-Abstract.html).
|
||||||
|
4. Jie Ren, Samyam Rajbhandari, Reza Yazdani Aminabadi, Olatunji Ruwase, Shuangyan Yang, Minjia Zhang, Dong Li, Yuxiong He. (2021) ZeRO-Offload: Democratizing Billion-Scale Model Training. [arXiv:2101.06840](https://arxiv.org/abs/2101.06840) and [USENIX ATC 2021](https://www.usenix.org/conference/atc21/presentation/ren-jie). [[paper]](https://arxiv.org/abs/2101.06840) [[slides]](https://www.usenix.org/system/files/atc21_slides_ren-jie.pdf) [[blog]](https://www.microsoft.com/en-us/research/blog/deepspeed-extreme-scale-model-training-for-everyone/)
|
||||||
|
5. Hanlin Tang, Shaoduo Gan, Ammar Ahmad Awan, Samyam Rajbhandari, Conglong Li, Xiangru Lian, Ji Liu, Ce Zhang, Yuxiong He. (2021) 1-bit Adam: Communication Efficient Large-Scale Training with Adam's Convergence Speed. [arXiv:2102.02888](https://arxiv.org/abs/2102.02888) and [ICML 2021](http://proceedings.mlr.press/v139/tang21a.html).
|
||||||
|
6. Samyam Rajbhandari, Olatunji Ruwase, Jeff Rasley, Shaden Smith, Yuxiong He. (2021) ZeRO-Infinity: Breaking the GPU Memory Wall for Extreme Scale Deep Learning. [arXiv:2104.07857](https://arxiv.org/abs/2104.07857) and [SC 2021](https://dl.acm.org/doi/abs/10.1145/3458817.3476205). [[paper]](https://arxiv.org/abs/2104.07857) [[slides]](docs/assets/files/SC21-ZeRO-Infinity.pdf) [[blog]](https://www.microsoft.com/en-us/research/blog/zero-infinity-and-deepspeed-unlocking-unprecedented-model-scale-for-deep-learning-training/)
|
||||||
|
7. Conglong Li, Ammar Ahmad Awan, Hanlin Tang, Samyam Rajbhandari, Yuxiong He. (2021) 1-bit LAMB: Communication Efficient Large-Scale Large-Batch Training with LAMB's Convergence Speed. [arXiv:2104.06069](https://arxiv.org/abs/2104.06069) and [HiPC 2022](https://hipc.org/advance-program/).
|
||||||
|
8. Conglong Li, Minjia Zhang, Yuxiong He. (2021) The Stability-Efficiency Dilemma: Investigating Sequence Length Warmup for Training GPT Models. [arXiv:2108.06084](https://arxiv.org/abs/2108.06084) and [NeurIPS 2022](https://openreview.net/forum?id=JpZ5du_Kdh).
|
||||||
|
9. Yucheng Lu, Conglong Li, Minjia Zhang, Christopher De Sa, Yuxiong He. (2022) Maximizing Communication Efficiency for Large-scale Training via 0/1 Adam. [arXiv:2202.06009](https://arxiv.org/abs/2202.06009).
|
||||||
|
10. Samyam Rajbhandari, Conglong Li, Zhewei Yao, Minjia Zhang, Reza Yazdani Aminabadi, Ammar Ahmad Awan, Jeff Rasley, Yuxiong He. (2022) DeepSpeed-MoE: Advancing Mixture-of-Experts Inference and Training to Power Next-Generation AI Scale [arXiv:2201.05596](https://arxiv.org/abs/2201.05596) and [ICML 2022](https://proceedings.mlr.press/v162/rajbhandari22a.html). [[pdf]](https://arxiv.org/abs/2201.05596) [[slides]](docs/assets/files/ICML-5mins.pdf) [[blog]](https://www.microsoft.com/en-us/research/blog/deepspeed-advancing-moe-inference-and-training-to-power-next-generation-ai-scale/)
|
||||||
|
11. Shaden Smith, Mostofa Patwary, Brandon Norick, Patrick LeGresley, Samyam Rajbhandari, Jared Casper, Zhun Liu, Shrimai Prabhumoye, George Zerveas, Vijay Korthikanti, Elton Zhang, Rewon Child, Reza Yazdani Aminabadi, Julie Bernauer, Xia Song, Mohammad Shoeybi, Yuxiong He, Michael Houston, Saurabh Tiwary, Bryan Catanzaro. (2022) Using DeepSpeed and Megatron to Train Megatron-Turing NLG 530B, A Large-Scale Generative Language Model [arXiv:2201.11990](https://arxiv.org/abs/2201.11990).
|
||||||
|
12. Xiaoxia Wu, Zhewei Yao, Minjia Zhang, Conglong Li, Yuxiong He. (2022) Extreme Compression for Pre-trained Transformers Made Simple and Efficient. [arXiv:2206.01859](https://arxiv.org/abs/2206.01859) and [NeurIPS 2022](https://openreview.net/forum?id=xNeAhc2CNAl).
|
||||||
|
13. Zhewei Yao, Reza Yazdani Aminabadi, Minjia Zhang, Xiaoxia Wu, Conglong Li, Yuxiong He. (2022) ZeroQuant: Efficient and Affordable Post-Training Quantization for Large-Scale Transformers. [arXiv:2206.01861](https://arxiv.org/abs/2206.01861) and [NeurIPS 2022](https://openreview.net/forum?id=f-fVCElZ-G1) [[slides]](docs/assets/files/zeroquant_series.pdf) [[blog]](https://www.microsoft.com/en-us/research/blog/deepspeed-compression-a-composable-library-for-extreme-compression-and-zero-cost-quantization/)
|
||||||
|
14. Reza Yazdani Aminabadi, Samyam Rajbhandari, Minjia Zhang, Ammar Ahmad Awan, Cheng Li, Du Li, Elton Zheng, Jeff Rasley, Shaden Smith, Olatunji Ruwase, Yuxiong He. (2022) DeepSpeed Inference: Enabling Efficient Inference of Transformer Models at Unprecedented Scale. [arXiv:2207.00032](https://arxiv.org/abs/2207.00032) and [SC 2022](https://dl.acm.org/doi/abs/10.5555/3571885.3571946). [[paper]](https://arxiv.org/abs/2207.00032) [[slides]](docs/assets/files/sc22-ds-inference.pdf) [[blog]](https://www.microsoft.com/en-us/research/blog/deepspeed-accelerating-large-scale-model-inference-and-training-via-system-optimizations-and-compression/)
|
||||||
|
15. Zhewei Yao, Xiaoxia Wu, Conglong Li, Connor Holmes, Minjia Zhang, Cheng Li, Yuxiong He. (2022) Random-LTD: Random and Layerwise Token Dropping Brings Efficient Training for Large-scale Transformers. [arXiv:2211.11586](https://arxiv.org/abs/2211.11586).
|
||||||
|
16. Conglong Li, Zhewei Yao, Xiaoxia Wu, Minjia Zhang, Yuxiong He. (2022) DeepSpeed Data Efficiency: Improving Deep Learning Model Quality and Training Efficiency via Efficient Data Sampling and Routing. [arXiv:2212.03597](https://arxiv.org/abs/2212.03597) [ENLSP2023 Workshop at NeurIPS2023](https://neurips2023-enlsp.github.io/)
|
||||||
|
17. Xiaoxia Wu, Cheng Li, Reza Yazdani Aminabadi, Zhewei Yao, Yuxiong He. (2023) Understanding INT4 Quantization for Transformer Models: Latency Speedup, Composability, and Failure Cases. [arXiv:2301.12017](https://arxiv.org/abs/2301.12017) and [ICML2023](https://icml.cc/Conferences/2023).
|
||||||
|
18. Syed Zawad, Cheng Li, Zhewei Yao, Elton Zheng, Yuxiong He, Feng Yan. (2023) DySR: Adaptive Super-Resolution via Algorithm and System Co-design. [ICLR:2023](https://openreview.net/forum?id=Pgtn4l6eKjv).
|
||||||
|
19. Sheng Shen, Zhewei Yao, Chunyuan Li, Trevor Darrell, Kurt Keutzer, Yuxiong He. (2023) Scaling Vision-Language Models with Sparse Mixture of Experts. [arXiv:2303.07226](https://arxiv.org/abs/2303.07226) and [Finding at EMNLP2023](https://2023.emnlp.org/).
|
||||||
|
20. Quentin Anthony, Ammar Ahmad Awan, Jeff Rasley, Yuxiong He, Aamir Shafi, Mustafa Abduljabbar, Hari Subramoni, Dhabaleswar Panda. (2023) MCR-DL: Mix-and-Match Communication Runtime for Deep Learning [arXiv:2303.08374](https://arxiv.org/abs/2303.08374) and will appear at IPDPS 2023.
|
||||||
|
21. Siddharth Singh, Olatunji Ruwase, Ammar Ahmad Awan, Samyam Rajbhandari, Yuxiong He, Abhinav Bhatele. (2023) A Hybrid Tensor-Expert-Data Parallelism Approach to Optimize Mixture-of-Experts Training [arXiv:2303.06318](https://arxiv.org/abs/2303.06318) and [ICS 2023](https://dl.acm.org/doi/10.1145/3577193.3593704).
|
||||||
|
22. Guanhua Wang, Heyang Qin, Sam Ade Jacobs, Xiaoxia Wu, Connor Holmes, Zhewei Yao, Samyam Rajbhandari, Olatunji Ruwase, Feng Yan, Lei Yang, Yuxiong He. (2023) ZeRO++: Extremely Efficient Collective Communication for Giant Model Training [arXiv:2306.10209](https://arxiv.org/abs/2306.10209) and [ML for Sys Workshop at NeurIPS2023](http://mlforsystems.org/) [[blog]](https://www.microsoft.com/en-us/research/blog/deepspeed-zero-a-leap-in-speed-for-llm-and-chat-model-training-with-4x-less-communication/)
|
||||||
|
23. Zhewei Yao, Xiaoxia Wu, Cheng Li, Stephen Youn, Yuxiong He. (2023) ZeroQuant-V2: Exploring Post-training Quantization in LLMs from Comprehensive Study to Low Rank Compensation [arXiv:2303.08302](https://arxiv.org/abs/2303.08302) and [ENLSP2023 Workshop at NeurIPS2023](https://neurips2023-enlsp.github.io/) [[slides]](docs/assets/files/zeroquant_series.pdf)
|
||||||
|
24. Pareesa Ameneh Golnari, Zhewei Yao, Yuxiong He. (2023) Selective Guidance: Are All the Denoising Steps of Guided Diffusion Important? [arXiv:2305.09847](https://arxiv.org/abs/2305.09847)
|
||||||
|
25. Zhewei Yao, Reza Yazdani Aminabadi, Olatunji Ruwase, Samyam Rajbhandari, Xiaoxia Wu, Ammar Ahmad Awan, Jeff Rasley, Minjia Zhang, Conglong Li, Connor Holmes, Zhongzhu Zhou, Michael Wyatt, Molly Smith, Lev Kurilenko, Heyang Qin, Masahiro Tanaka, Shuai Che, Shuaiwen Leon Song, Yuxiong He. (2023) DeepSpeed-Chat: Easy, Fast and Affordable RLHF Training of ChatGPT-like Models at All Scales [arXiv:2308.01320](https://arxiv.org/abs/2308.01320).
|
||||||
|
26. Xiaoxia Wu, Zhewei Yao, Yuxiong He. (2023) ZeroQuant-FP: A Leap Forward in LLMs Post-Training W4A8 Quantization Using Floating-Point Formats [arXiv:2307.09782](https://arxiv.org/abs/2307.09782) and [ENLSP2023 Workshop at NeurIPS2023](https://neurips2023-enlsp.github.io/) [[slides]](docs/assets/files/zeroquant_series.pdf)
|
||||||
|
27. Zhewei Yao, Xiaoxia Wu, Conglong Li, Minjia Zhang, Heyang Qin, Olatunji Ruwase, Ammar Ahmad Awan, Samyam Rajbhandari, Yuxiong He. (2023) DeepSpeed-VisualChat: Multi-Round Multi-Image Interleave Chat via Multi-Modal Causal Attention [arXiv:2309.14327](https://arxiv.org/pdf/2309.14327.pdf)
|
||||||
|
28. Shuaiwen Leon Song, Bonnie Kruft, Minjia Zhang, Conglong Li, Shiyang Chen, Chengming Zhang, Masahiro Tanaka, Xiaoxia Wu, Jeff Rasley, Ammar Ahmad Awan, Connor Holmes, Martin Cai, Adam Ghanem, Zhongzhu Zhou, Yuxiong He, et al. (2023) DeepSpeed4Science Initiative: Enabling Large-Scale Scientific Discovery through Sophisticated AI System Technologies [arXiv:2310.04610](https://arxiv.org/abs/2310.04610) [[blog]](https://www.microsoft.com/en-us/research/blog/announcing-the-deepspeed4science-initiative-enabling-large-scale-scientific-discovery-through-sophisticated-ai-system-technologies/)
|
||||||
|
29. Zhewei Yao, Reza Yazdani Aminabadi, Stephen Youn, Xiaoxia Wu, Elton Zheng, Yuxiong He. (2023) ZeroQuant-HERO: Hardware-Enhanced Robust Optimized Post-Training Quantization Framework for W8A8 Transformers [arXiv:2310.17723](https://arxiv.org/abs/2310.17723)
|
||||||
|
|
||||||
|
30. Xiaoxia Wu, Haojun Xia, Stephen Youn, Zhen Zheng, Shiyang Chen, Arash Bakhtiari, Michael Wyatt, Reza Yazdani Aminabadi, Yuxiong He, Olatunji Ruwase, Leon Song, Zhewei Yao (2023) ZeroQuant(4+2): Redefining LLMs Quantization with a New FP6-Centric Strategy for Diverse Generative Tasks [arXiv:2312.08583](https://arxiv.org/abs/2312.08583)
|
||||||
|
|
||||||
|
31. Haojun Xia, Zhen Zheng, Xiaoxia Wu, Shiyang Chen, Zhewei Yao, Stephen Youn, Arash Bakhtiari, Michael Wyatt, Donglin Zhuang, Zhongzhu Zhou, Olatunji Ruwase, Yuxiong He, Shuaiwen Leon Song. (2024) FP6-LLM: Efficiently Serving Large Language Models Through FP6-Centric Algorithm-System Co-Design [arXiv:2401.14112](https://arxiv.org/abs/2401.14112)
|
||||||
|
32. Sam Ade Jacobs, Masahiro Tanaka, Chengming Zhang, Minjia Zhang, Reza Yazdani Aminadabi, Shuaiwen Leon Song, Samyam Rajbhandari, Yuxiong He. (2024) [System Optimizations for Enabling Training of Extreme Long Sequence Transformer Models](https://dl.acm.org/doi/10.1145/3662158.3662806)
|
||||||
|
33. Xinyu Lian, Sam Ade Jacobs, Lev Kurilenko, Masahiro Tanaka, Stas Bekman, Olatunji Ruwase, Minjia Zhang. (2024) Universal Checkpointing: Efficient and Flexible Checkpointing for Large Scale Distributed Training [arXiv:2406.18820](https://arxiv.org/abs/2406.18820)
|
||||||
|
34. Stas Bekman, Samyam Rajbhandari, Michael Wyatt, Jeff Rasley, Tunji Ruwase, Zhewei Yao, Aurick Qiao, Yuxiong He. (2025) Arctic Long Sequence Training: Scalable And Efficient Training For Multi-Million Token Sequences [arXiv:2506.13996](https://arxiv.org/abs/2506.13996)
|
||||||
|
35. Tingfeng Lan, Yusen Wu, Bin Ma, Zhaoyuan Su, Rui Yang, Tekin Bicer, Masahiro Tanaka, Olatunji Ruwase, Dong Li, Yue Cheng. (2025) ZenFlow: Enabling Stall-Free Offloading Training via Asynchronous Updates [arXiv:2505.12242](https://arxiv.org/abs/2505.12242)
|
||||||
|
36. Kayhan Behdin, Ata Fatahibaarzi, Qingquan Song, Yun Dai, Aman Gupta, Zhipeng Wang, Hejian Sang, Shao Tang, Gregory Dexter, Sirou Zhu, Siyu Zhu, Tejas Dharamsi, Vignesh Kothapalli, Zhoutong Fu, Yihan Cao, Pin-Lun Hsu, Fedor Borisyuk, Natesh S. Pillai, Luke Simon, Rahul Mazumder.(2025) Scaling Down, Serving Fast: Compressing and Deploying Efficient LLMs for Recommendation Systems [EMNLP 2025](https://aclanthology.org/2025.emnlp-industry.119/)
|
||||||
|
37. Xinyu Lian, Masahiro Tanaka, Olatunji Ruwase, Minjia Zhang. (2026) SuperOffload: Unleashing the Power of Large-Scale LLM Training on Superchips [arxiv](https://arxiv.org/abs/2509.21271), [ASPLOS 2026](https://www.asplos-conference.org/asplos2026)
|
||||||
|
|
||||||
|
# Videos
|
||||||
|
1. DeepSpeed KDD 2020 Tutorial
|
||||||
|
1. [Overview](https://www.youtube.com/watch?v=CaseqC45DNc&list=PLa85ZdUjfWS21mgibJ2vCvLziprjpKoW0&index=29)
|
||||||
|
2. [ZeRO + large model training](https://www.youtube.com/watch?v=y4_bCiAsIAk&list=PLa85ZdUjfWS21mgibJ2vCvLziprjpKoW0&index=28)
|
||||||
|
3. [17B T-NLG demo](https://www.youtube.com/watch?v=9V-ZbP92drg&list=PLa85ZdUjfWS21mgibJ2vCvLziprjpKoW0&index=27)
|
||||||
|
4. [Fastest BERT training + RScan tuning](https://www.youtube.com/watch?v=o1K-ZG9F6u0&list=PLa85ZdUjfWS21mgibJ2vCvLziprjpKoW0&index=26)
|
||||||
|
5. DeepSpeed hands on deep dive: [part 1](https://www.youtube.com/watch?v=_NOk-mBwDYg&list=PLa85ZdUjfWS21mgibJ2vCvLziprjpKoW0&index=92), [part 2](https://www.youtube.com/watch?v=sG6_c4VXLww&list=PLa85ZdUjfWS21mgibJ2vCvLziprjpKoW0&index=94), [part 3](https://www.youtube.com/watch?v=k9yPkBTayos&list=PLa85ZdUjfWS21mgibJ2vCvLziprjpKoW0&index=93)
|
||||||
|
6. [FAQ](https://www.youtube.com/watch?v=nsHu6vEgPew&list=PLa85ZdUjfWS21mgibJ2vCvLziprjpKoW0&index=24)
|
||||||
|
2. Microsoft Research Webinar
|
||||||
|
* Registration is free and all videos are available on-demand.
|
||||||
|
* [ZeRO & Fastest BERT: Increasing the scale and speed of deep learning training in DeepSpeed](https://note.microsoft.com/MSR-Webinar-DeepSpeed-Registration-On-Demand.html).
|
||||||
|
3. [DeepSpeed on AzureML](https://youtu.be/yBVXR8G8Bg8)
|
||||||
|
4. [Large Model Training and Inference with DeepSpeed // Samyam Rajbhandari // LLMs in Prod Conference](https://www.youtube.com/watch?v=cntxC3g22oU) [[slides]](docs/assets/files/presentation-mlops.pdf)
|
||||||
|
5. Community Tutorials
|
||||||
|
* [DeepSpeed: All the tricks to scale to gigantic models (Mark Saroufim)](https://www.youtube.com/watch?v=pDGI668pNg0)
|
||||||
|
* [Turing-NLG, DeepSpeed and the ZeRO optimizer (Yannic Kilcher)](https://www.youtube.com/watch?v=tC01FRB0M7w)
|
||||||
|
* [Ultimate Guide To Scaling ML Models (The AI Epiphany)](https://www.youtube.com/watch?v=hc0u4avAkuM)
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# WeHub 来源说明
|
||||||
|
|
||||||
|
- 原始项目:`deepspeedai/DeepSpeed`
|
||||||
|
- 原始仓库:https://github.com/deepspeedai/DeepSpeed
|
||||||
|
- 导入方式:上游默认分支的最新快照
|
||||||
|
- 原作者、版权和许可证信息以原始仓库及本仓库 LICENSE 为准
|
||||||
|
- 本文件仅用于记录来源,不代表 WeHub 是原项目作者
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Reporting security issues
|
||||||
|
|
||||||
|
Please report security issues privately using [the vulnerability submission form](https://github.com/deepspeedai/deepspeed/security/advisories/new).
|
||||||
|
|
||||||
|
## Issue triage
|
||||||
|
|
||||||
|
Reports will then be triaged by the maintainers.
|
||||||
|
|
||||||
|
## Threat model
|
||||||
|
|
||||||
|
Please see [PyTorch's Security Policy](https://github.com/pytorch/pytorch/blob/main/SECURITY.md) for more information and recommendations on how to securely interact with models.
|
||||||
|
|
||||||
|
## Issue severity
|
||||||
|
|
||||||
|
We will determine the risk of each issue, taking into account our experience dealing with past issues, versions affected, common defaults, and use cases. We use the following severity categories:
|
||||||
|
|
||||||
|
### CRITICAL Severity
|
||||||
|
|
||||||
|
Vulnerabilities that allow remote attackers to execute arbitrary code, take full control of the system, or significantly compromise confidentiality, integrity, or availability without any interaction or privileges needed, examples include remote code execution via network, deserialization issues that allow exploit chains. Generally those issues which are rated as CVSS ≥ 9.0.
|
||||||
|
|
||||||
|
### HIGH Severity
|
||||||
|
|
||||||
|
Serious security flaws that allow elevated impact—like RCE in specific, limited contexts or significant data loss—but require advanced conditions or some trust, examples include RCE in advanced deployment modes (e.g. multi-node), or high impact issues where some sort of privileged network access is required. These issues typically have CVSS scores between 7.0 and 8.9
|
||||||
|
|
||||||
|
### MODERATE Severity
|
||||||
|
|
||||||
|
Vulnerabilities that cause denial of service or partial disruption, but do not allow arbitrary code execution or data breach and have limited impact. These issues have a CVSS rating between 4.0 and 6.9
|
||||||
|
|
||||||
|
### LOW Severity
|
||||||
|
|
||||||
|
Minor issues such as informational disclosures, logging errors, non-exploitable flaws, or weaknesses that require local or high-privilege access and offer negligible impact. Examples include side channel attacks or hash collisions. These issues often have CVSS scores less than 4.0
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
# Third-Party Notices
|
||||||
|
|
||||||
|
This file records third-party source notices for code incorporated into
|
||||||
|
DeepSpeed source files.
|
||||||
|
|
||||||
|
## TorchTitan
|
||||||
|
|
||||||
|
The following files contain portions derived from TorchTitan:
|
||||||
|
|
||||||
|
- `deepspeed/module_inject/auto_ep_layer.py`
|
||||||
|
- `deepspeed/moe/ep_experts.py`
|
||||||
|
- `deepspeed/moe/ep_kernels.py`
|
||||||
|
- `deepspeed/moe/ep_router.py`
|
||||||
|
|
||||||
|
Source project: https://github.com/pytorch/torchtitan
|
||||||
|
|
||||||
|
TorchTitan is licensed under the BSD 3-Clause License:
|
||||||
|
|
||||||
|
```text
|
||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
(c) Meta Platforms, Inc. and affiliates.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
may be used to endorse or promote products derived from this software without
|
||||||
|
specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
```
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Copyright (c) Microsoft Corporation.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
# DeepSpeed Team
|
||||||
|
|
||||||
|
from .abstract_accelerator import DeepSpeedAccelerator
|
||||||
|
from .real_accelerator import get_accelerator, set_accelerator, is_current_accelerator_supported
|
||||||
@@ -0,0 +1,303 @@
|
|||||||
|
# Copyright (c) Microsoft Corporation.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
# DeepSpeed Team
|
||||||
|
|
||||||
|
import abc
|
||||||
|
from abc import ABC
|
||||||
|
|
||||||
|
|
||||||
|
class DeepSpeedAccelerator(ABC):
|
||||||
|
supports_nvtx_domain = False
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._name = None
|
||||||
|
self._communication_backend_name = None
|
||||||
|
self._compile_backend = None
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def is_synchronized_device(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def use_host_timers(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def resolves_data_dependency(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def handles_memory_backpressure(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
# Device APIs
|
||||||
|
@abc.abstractmethod
|
||||||
|
def device_name(self, device_index):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def device(self, device_index):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def set_device(self, device_index):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def current_device(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def current_device_name(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def device_count(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def synchronize(self, device_index=None):
|
||||||
|
...
|
||||||
|
|
||||||
|
# RNG APIs
|
||||||
|
@abc.abstractmethod
|
||||||
|
def random(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def set_rng_state(self, new_state, device_index=None):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_rng_state(self, device_index=None):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def manual_seed(self, seed):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def manual_seed_all(self, seed):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def initial_seed(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def default_generator(self, device_index):
|
||||||
|
...
|
||||||
|
|
||||||
|
# Streams/Events
|
||||||
|
@property
|
||||||
|
@abc.abstractmethod
|
||||||
|
def Stream(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def stream(self, stream):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def current_stream(self, device_index=None):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def default_stream(self, device_index=None):
|
||||||
|
...
|
||||||
|
|
||||||
|
@property
|
||||||
|
@abc.abstractmethod
|
||||||
|
def Event(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
# Memory management
|
||||||
|
@abc.abstractmethod
|
||||||
|
def empty_cache(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def memory_allocated(self, device_index=None):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def max_memory_allocated(self, device_index=None):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def reset_max_memory_allocated(self, device_index=None):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def memory_cached(self, device_index=None):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def max_memory_cached(self, device_index=None):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def reset_max_memory_cached(self, device_index=None):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def memory_stats(self, device_index=None):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def reset_peak_memory_stats(self, device_index=None):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def memory_reserved(self, device_index=None):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def max_memory_reserved(self, device_index=None):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def total_memory(self, device_index=None):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def available_memory(self, device_index=None):
|
||||||
|
...
|
||||||
|
|
||||||
|
# Data types
|
||||||
|
@abc.abstractmethod
|
||||||
|
def is_bf16_supported(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def is_fp16_supported(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def supported_dtypes(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
@abc.abstractmethod
|
||||||
|
def is_available(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def range_push(self, msg, domain=None, category=None):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def range_pop(self, domain=None):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def lazy_call(self, callback):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def communication_backend_name(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def is_triton_supported(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
# Graph operations
|
||||||
|
@abc.abstractmethod
|
||||||
|
def create_graph(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def capture_to_graph(self, graph, pool=None, stream=None):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def replay_graph(self, graph):
|
||||||
|
...
|
||||||
|
|
||||||
|
# Tensor operations
|
||||||
|
@property
|
||||||
|
@abc.abstractmethod
|
||||||
|
def BFloat16Tensor(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@property
|
||||||
|
@abc.abstractmethod
|
||||||
|
def ByteTensor(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@property
|
||||||
|
@abc.abstractmethod
|
||||||
|
def DoubleTensor(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@property
|
||||||
|
@abc.abstractmethod
|
||||||
|
def FloatTensor(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@property
|
||||||
|
@abc.abstractmethod
|
||||||
|
def HalfTensor(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@property
|
||||||
|
@abc.abstractmethod
|
||||||
|
def IntTensor(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@property
|
||||||
|
@abc.abstractmethod
|
||||||
|
def LongTensor(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def pin_memory(self, tensor, align_bytes=1):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def is_pinned(self, tensor):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def on_accelerator(self, tensor):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def op_builder_dir(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
# create an instance of op builder, specified by class_name
|
||||||
|
@abc.abstractmethod
|
||||||
|
def create_op_builder(self, class_name):
|
||||||
|
...
|
||||||
|
|
||||||
|
# return an op builder class, specified by class_name
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_op_builder(self, class_name):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def build_extension(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def export_envs(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def visible_devices_envs(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def set_visible_devices_envs(self, current_env, local_accelerator_ids):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_compile_backend(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def set_compile_backend(self, backend):
|
||||||
|
...
|
||||||
@@ -0,0 +1,358 @@
|
|||||||
|
# Copyright (c) Microsoft Corporation.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
# DeepSpeed Team
|
||||||
|
|
||||||
|
from .abstract_accelerator import DeepSpeedAccelerator
|
||||||
|
|
||||||
|
# During setup stage torch may not be installed, pass on no torch will
|
||||||
|
# allow op builder related API to be executed.
|
||||||
|
try:
|
||||||
|
import torch
|
||||||
|
except ImportError as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
import oneccl_bindings_for_pytorch # noqa: F401 # type: ignore
|
||||||
|
oneccl_imported_p = True
|
||||||
|
except ImportError as e:
|
||||||
|
oneccl_imported_p = False
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
# accelerator for Intel CPU
|
||||||
|
class CPU_Accelerator(DeepSpeedAccelerator):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._name = 'cpu'
|
||||||
|
self._compile_backend = "inductor"
|
||||||
|
if oneccl_imported_p:
|
||||||
|
self._communication_backend_name = 'ccl'
|
||||||
|
else:
|
||||||
|
# fallback to gloo if oneccl_binding_for_pytorch is not installed
|
||||||
|
self._communication_backend_name = 'gloo'
|
||||||
|
try:
|
||||||
|
import psutil
|
||||||
|
mem = psutil.Process().memory_info().rss
|
||||||
|
self.max_mem = mem
|
||||||
|
except ImportError as e:
|
||||||
|
self.max_mem = 0
|
||||||
|
|
||||||
|
def is_synchronized_device(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def use_host_timers(self):
|
||||||
|
return self.is_synchronized_device()
|
||||||
|
|
||||||
|
def resolves_data_dependency(self):
|
||||||
|
return self.is_synchronized_device()
|
||||||
|
|
||||||
|
def handles_memory_backpressure(self):
|
||||||
|
return self.is_synchronized_device()
|
||||||
|
|
||||||
|
# Device APIs
|
||||||
|
def device_name(self, device_index=None):
|
||||||
|
return 'cpu'
|
||||||
|
|
||||||
|
def device(self, device_index=None):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def set_device(self, device_index):
|
||||||
|
return
|
||||||
|
|
||||||
|
def current_device(self):
|
||||||
|
return os.environ.get('LOCAL_RANK', 0)
|
||||||
|
|
||||||
|
def current_device_name(self):
|
||||||
|
return 'cpu'
|
||||||
|
|
||||||
|
def device_count(self):
|
||||||
|
device_count = int(os.environ.get('LOCAL_SIZE', 0))
|
||||||
|
if device_count > 0:
|
||||||
|
return device_count
|
||||||
|
else:
|
||||||
|
from deepspeed.utils.numa import get_numa_cores
|
||||||
|
# Count NUMA node for number of cpu accelerators. On machine with HBM
|
||||||
|
# In flat mode, HBM is in separate NUMA node with no cores on this node.
|
||||||
|
# Ignore these NUMA nodes with no cores.
|
||||||
|
numa_core_lists = get_numa_cores()
|
||||||
|
if not numa_core_lists:
|
||||||
|
return 1
|
||||||
|
numa_count = 0
|
||||||
|
prev_core_list = []
|
||||||
|
for core_list in numa_core_lists:
|
||||||
|
if len(core_list) > 0 and core_list != prev_core_list:
|
||||||
|
numa_count += 1
|
||||||
|
prev_core_list = core_list
|
||||||
|
return numa_count
|
||||||
|
|
||||||
|
def synchronize(self, device_index=None):
|
||||||
|
return
|
||||||
|
|
||||||
|
# RNG APIs
|
||||||
|
def random(self):
|
||||||
|
return torch.random
|
||||||
|
|
||||||
|
def set_rng_state(self, new_state, device_index=None):
|
||||||
|
if device_index is None:
|
||||||
|
return torch.set_rng_state(new_state)
|
||||||
|
return torch.set_rng_state(new_state, device_index)
|
||||||
|
|
||||||
|
def get_rng_state(self, device_index=None):
|
||||||
|
return torch.get_rng_state()
|
||||||
|
|
||||||
|
def manual_seed(self, seed):
|
||||||
|
return torch.manual_seed(seed)
|
||||||
|
|
||||||
|
def manual_seed_all(self, seed):
|
||||||
|
return torch.manual_seed(seed)
|
||||||
|
|
||||||
|
def initial_seed(self):
|
||||||
|
return torch.initial_seed()
|
||||||
|
|
||||||
|
def default_generator(self, device_index):
|
||||||
|
return torch.default_generator
|
||||||
|
|
||||||
|
# Streams/Events
|
||||||
|
@property
|
||||||
|
def Stream(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def stream(self, stream):
|
||||||
|
from deepspeed.runtime.utils import noop_context
|
||||||
|
return noop_context()
|
||||||
|
|
||||||
|
def current_stream(self, device_index=None):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def default_stream(self, device_index=None):
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def Event(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Memory management
|
||||||
|
def empty_cache(self):
|
||||||
|
return
|
||||||
|
|
||||||
|
def get_rss(self):
|
||||||
|
import psutil
|
||||||
|
mem = psutil.Process().memory_info().rss
|
||||||
|
if mem > self.max_mem:
|
||||||
|
self.max_mem = mem
|
||||||
|
return mem
|
||||||
|
|
||||||
|
def reset_rss(self):
|
||||||
|
import psutil
|
||||||
|
mem = psutil.Process().memory_info().rss
|
||||||
|
self.max_mem = mem
|
||||||
|
return mem
|
||||||
|
|
||||||
|
def memory_allocated(self, device_index=None):
|
||||||
|
return self.get_rss()
|
||||||
|
|
||||||
|
def max_memory_allocated(self, device_index=None):
|
||||||
|
self.get_rss()
|
||||||
|
return self.max_mem
|
||||||
|
|
||||||
|
def reset_max_memory_allocated(self, device_index=None):
|
||||||
|
self.reset_rss()
|
||||||
|
return
|
||||||
|
|
||||||
|
def memory_cached(self, device_index=None):
|
||||||
|
return self.get_rss()
|
||||||
|
|
||||||
|
def max_memory_cached(self, device_index=None):
|
||||||
|
self.get_rss()
|
||||||
|
return self.max_mem
|
||||||
|
|
||||||
|
def reset_max_memory_cached(self, device_index=None):
|
||||||
|
self.reset_rss()
|
||||||
|
return
|
||||||
|
|
||||||
|
def memory_stats(self, device_index=None):
|
||||||
|
mem = self.get_rss()
|
||||||
|
mem_stat = {}
|
||||||
|
mem_stat['allocated_bytes.all.current'] = mem
|
||||||
|
mem_stat['allocated_bytes.all.peak'] = self.max_mem
|
||||||
|
return mem_stat
|
||||||
|
|
||||||
|
def reset_peak_memory_stats(self, device_index=None):
|
||||||
|
self.reset_rss()
|
||||||
|
return
|
||||||
|
|
||||||
|
def memory_reserved(self, device_index=None):
|
||||||
|
return self.get_rss()
|
||||||
|
|
||||||
|
def max_memory_reserved(self, device_index=None):
|
||||||
|
self.get_rss()
|
||||||
|
return self.max_mem
|
||||||
|
|
||||||
|
def total_memory(self, device_index=None):
|
||||||
|
import psutil
|
||||||
|
return psutil.virtual_memory().total
|
||||||
|
|
||||||
|
def available_memory(self, device_index=None):
|
||||||
|
import psutil
|
||||||
|
return psutil.virtual_memory().available
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
def is_available(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def range_push(self, msg, domain=None, category=None):
|
||||||
|
# TODO itt is currently not supported yet
|
||||||
|
# return torch.profiler.itt.range_push(msg)
|
||||||
|
return
|
||||||
|
|
||||||
|
def range_pop(self, domain=None):
|
||||||
|
# TODO itt is currently not supported yet
|
||||||
|
# return torch.profiler.itt.range_pop()
|
||||||
|
return
|
||||||
|
|
||||||
|
def lazy_call(self, callback):
|
||||||
|
return callback()
|
||||||
|
|
||||||
|
def communication_backend_name(self):
|
||||||
|
return self._communication_backend_name
|
||||||
|
|
||||||
|
def is_triton_supported(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Data types
|
||||||
|
def is_bf16_supported(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def is_fp16_supported(self):
|
||||||
|
try:
|
||||||
|
if torch.ops.mkldnn._is_mkldnn_fp16_supported():
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def supported_dtypes(self):
|
||||||
|
supported_dtypes = [torch.float, torch.bfloat16]
|
||||||
|
if self.is_fp16_supported():
|
||||||
|
supported_dtypes.append(torch.float16)
|
||||||
|
return supported_dtypes
|
||||||
|
|
||||||
|
# Graph operations
|
||||||
|
def create_graph(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def capture_to_graph(self, graph, pool=None, stream=None):
|
||||||
|
from deepspeed.runtime.utils import noop_context
|
||||||
|
return noop_context()
|
||||||
|
|
||||||
|
def replay_graph(self, graph):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Tensor operations
|
||||||
|
@property
|
||||||
|
def BFloat16Tensor(self):
|
||||||
|
return torch.BFloat16Tensor
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ByteTensor(self):
|
||||||
|
return torch.ByteTensor
|
||||||
|
|
||||||
|
@property
|
||||||
|
def DoubleTensor(self):
|
||||||
|
return torch.DoubleTensor
|
||||||
|
|
||||||
|
@property
|
||||||
|
def FloatTensor(self):
|
||||||
|
return torch.FloatTensor
|
||||||
|
|
||||||
|
@property
|
||||||
|
def HalfTensor(self):
|
||||||
|
return torch.HalfTensor
|
||||||
|
|
||||||
|
@property
|
||||||
|
def IntTensor(self):
|
||||||
|
return torch.IntTensor
|
||||||
|
|
||||||
|
@property
|
||||||
|
def LongTensor(self):
|
||||||
|
return torch.LongTensor
|
||||||
|
|
||||||
|
def pin_memory(self, tensor, align_bytes=1):
|
||||||
|
return tensor
|
||||||
|
|
||||||
|
def is_pinned(self, tensor):
|
||||||
|
return tensor.is_pinned()
|
||||||
|
|
||||||
|
def op_builder_dir(self):
|
||||||
|
try:
|
||||||
|
# is op_builder from deepspeed or a 3p version? this should only succeed if it's deepspeed
|
||||||
|
# if successful this also means we're doing a local install and not JIT compile path
|
||||||
|
from op_builder import __deepspeed__ # noqa: F401 # type: ignore
|
||||||
|
return "op_builder.cpu"
|
||||||
|
except ImportError:
|
||||||
|
return "deepspeed.ops.op_builder.cpu"
|
||||||
|
|
||||||
|
def on_accelerator(self, tensor):
|
||||||
|
device_str = str(tensor.device)
|
||||||
|
if device_str.startswith('cpu'):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# create an instance of op builder and return, name specified by class_name
|
||||||
|
def create_op_builder(self, op_name):
|
||||||
|
builder_class = self.get_op_builder(op_name)
|
||||||
|
if builder_class is not None:
|
||||||
|
return builder_class()
|
||||||
|
return None
|
||||||
|
|
||||||
|
# return an op builder class, name specified by class_name
|
||||||
|
def get_op_builder(self, class_name):
|
||||||
|
try:
|
||||||
|
# is op_builder from deepspeed or a 3p version? this should only succeed if it's deepspeed
|
||||||
|
# if successful this also means we're doing a local install and not JIT compile path
|
||||||
|
from op_builder import __deepspeed__ # noqa: F401 # type: ignore
|
||||||
|
from op_builder.cpu import AsyncIOBuilder, CCLCommBuilder, ShareMemCommBuilder, FusedAdamBuilder, CPUAdamBuilder, NotImplementedBuilder
|
||||||
|
except ImportError:
|
||||||
|
from deepspeed.ops.op_builder.cpu import AsyncIOBuilder, CCLCommBuilder, ShareMemCommBuilder, FusedAdamBuilder, CPUAdamBuilder, NotImplementedBuilder
|
||||||
|
|
||||||
|
if class_name == "CCLCommBuilder":
|
||||||
|
return CCLCommBuilder
|
||||||
|
elif class_name == "ShareMemCommBuilder":
|
||||||
|
return ShareMemCommBuilder
|
||||||
|
elif class_name == "FusedAdamBuilder":
|
||||||
|
return FusedAdamBuilder
|
||||||
|
elif class_name == "CPUAdamBuilder":
|
||||||
|
return CPUAdamBuilder
|
||||||
|
elif class_name == "AsyncIOBuilder":
|
||||||
|
return AsyncIOBuilder
|
||||||
|
else:
|
||||||
|
# return a NotImplementedBuilder to avoid get NoneType[Name] in unit tests
|
||||||
|
return NotImplementedBuilder
|
||||||
|
|
||||||
|
def build_extension(self):
|
||||||
|
from torch.utils.cpp_extension import BuildExtension
|
||||||
|
return BuildExtension
|
||||||
|
|
||||||
|
def export_envs(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
# TODO: cpu's visible envs is confirmed, keep as CUDA_VISIBLE_DEVICES
|
||||||
|
def visible_devices_envs(self):
|
||||||
|
return ['CUDA_VISIBLE_DEVICES']
|
||||||
|
|
||||||
|
def set_visible_devices_envs(self, current_env, local_accelerator_ids):
|
||||||
|
for env in self.visible_devices_envs():
|
||||||
|
current_env[env] = ",".join(map(str, local_accelerator_ids))
|
||||||
|
|
||||||
|
def get_compile_backend(self):
|
||||||
|
return self._compile_backend
|
||||||
|
|
||||||
|
def set_compile_backend(self, backend):
|
||||||
|
supported_backends = torch._dynamo.list_backends(exclude_tags=())
|
||||||
|
if backend in supported_backends:
|
||||||
|
self._compile_backend = backend
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
f"{backend} not supported by {self.device_name()}. Supported Backends are {supported_backends}")
|
||||||
@@ -0,0 +1,404 @@
|
|||||||
|
# Copyright (c) Microsoft Corporation.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
# DeepSpeed Team
|
||||||
|
|
||||||
|
import functools
|
||||||
|
import os
|
||||||
|
import pkgutil
|
||||||
|
import importlib
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from .abstract_accelerator import DeepSpeedAccelerator
|
||||||
|
# During setup stage torch may not be installed, pass on no torch will
|
||||||
|
# allow op builder related API to be executed.
|
||||||
|
try:
|
||||||
|
import torch.cuda
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
import nvtx
|
||||||
|
except ImportError:
|
||||||
|
nvtx = None
|
||||||
|
|
||||||
|
# Delay import pynvml to avoid import error when CUDA is not available
|
||||||
|
pynvml = None
|
||||||
|
|
||||||
|
|
||||||
|
class CUDA_Accelerator(DeepSpeedAccelerator):
|
||||||
|
supports_nvtx_domain = True
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._name = 'cuda'
|
||||||
|
self._communication_backend_name = 'nccl' if sys.platform != 'win32' else 'gloo'
|
||||||
|
self._compile_backend = "inductor"
|
||||||
|
self._nvtx_domains = {}
|
||||||
|
if pynvml is None:
|
||||||
|
self._init_pynvml()
|
||||||
|
|
||||||
|
def _init_pynvml(self):
|
||||||
|
global pynvml
|
||||||
|
try:
|
||||||
|
import pynvml
|
||||||
|
except ImportError:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
pynvml.nvmlInit()
|
||||||
|
except pynvml.NVMLError:
|
||||||
|
pynvml = None
|
||||||
|
return
|
||||||
|
|
||||||
|
def is_synchronized_device(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def use_host_timers(self):
|
||||||
|
return self.is_synchronized_device()
|
||||||
|
|
||||||
|
def resolves_data_dependency(self):
|
||||||
|
return self.is_synchronized_device()
|
||||||
|
|
||||||
|
def handles_memory_backpressure(self):
|
||||||
|
return self.is_synchronized_device()
|
||||||
|
|
||||||
|
# Device APIs
|
||||||
|
def device_name(self, device_index=None):
|
||||||
|
if device_index is None:
|
||||||
|
return 'cuda'
|
||||||
|
return 'cuda:{}'.format(device_index)
|
||||||
|
|
||||||
|
def communication_backend_version(self):
|
||||||
|
return torch.cuda.nccl.version()
|
||||||
|
|
||||||
|
def device(self, device_index=None):
|
||||||
|
return torch.device('cuda', device_index)
|
||||||
|
|
||||||
|
def set_device(self, device_index):
|
||||||
|
torch.cuda.set_device(device_index)
|
||||||
|
|
||||||
|
def current_device(self):
|
||||||
|
return torch.cuda.current_device()
|
||||||
|
|
||||||
|
def current_device_name(self):
|
||||||
|
return 'cuda:{}'.format(torch.cuda.current_device())
|
||||||
|
|
||||||
|
def device_count(self):
|
||||||
|
return torch.cuda.device_count()
|
||||||
|
|
||||||
|
def synchronize(self, device_index=None):
|
||||||
|
return torch.cuda.synchronize(device_index)
|
||||||
|
|
||||||
|
# RNG APIs
|
||||||
|
def random(self):
|
||||||
|
return torch.random
|
||||||
|
|
||||||
|
def set_rng_state(self, new_state, device_index=None):
|
||||||
|
if device_index is None:
|
||||||
|
return torch.cuda.set_rng_state(new_state)
|
||||||
|
|
||||||
|
return torch.cuda.set_rng_state(new_state, device_index)
|
||||||
|
|
||||||
|
def get_rng_state(self, device_index=None):
|
||||||
|
if device_index is None:
|
||||||
|
return torch.cuda.get_rng_state()
|
||||||
|
|
||||||
|
return torch.cuda.get_rng_state(device_index)
|
||||||
|
|
||||||
|
def manual_seed(self, seed):
|
||||||
|
return torch.cuda.manual_seed(seed)
|
||||||
|
|
||||||
|
def manual_seed_all(self, seed):
|
||||||
|
return torch.cuda.manual_seed_all(seed)
|
||||||
|
|
||||||
|
def initial_seed(self):
|
||||||
|
return torch.cuda.initial_seed()
|
||||||
|
|
||||||
|
def default_generator(self, device_index):
|
||||||
|
return torch.cuda.default_generators[device_index]
|
||||||
|
|
||||||
|
# Streams/Events
|
||||||
|
@property
|
||||||
|
def Stream(self):
|
||||||
|
return torch.cuda.Stream
|
||||||
|
|
||||||
|
def stream(self, stream):
|
||||||
|
return torch.cuda.stream(stream)
|
||||||
|
|
||||||
|
def current_stream(self, device_index=None):
|
||||||
|
return torch.cuda.current_stream(device_index)
|
||||||
|
|
||||||
|
def default_stream(self, device_index=None):
|
||||||
|
return torch.cuda.default_stream(device_index)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def Event(self):
|
||||||
|
return torch.cuda.Event
|
||||||
|
|
||||||
|
# Memory management
|
||||||
|
def empty_cache(self):
|
||||||
|
return torch.cuda.empty_cache()
|
||||||
|
|
||||||
|
def memory_allocated(self, device_index=None):
|
||||||
|
return torch.cuda.memory_allocated(device_index)
|
||||||
|
|
||||||
|
def max_memory_allocated(self, device_index=None):
|
||||||
|
return torch.cuda.max_memory_allocated(device_index)
|
||||||
|
|
||||||
|
def reset_max_memory_allocated(self, device_index=None):
|
||||||
|
return torch.cuda.reset_max_memory_allocated(device_index)
|
||||||
|
|
||||||
|
def memory_cached(self, device_index=None):
|
||||||
|
return torch.cuda.memory_cached(device_index)
|
||||||
|
|
||||||
|
def max_memory_cached(self, device_index=None):
|
||||||
|
return torch.cuda.max_memory_cached(device_index)
|
||||||
|
|
||||||
|
def reset_max_memory_cached(self, device_index=None):
|
||||||
|
return torch.cuda.reset_max_memory_cached(device_index)
|
||||||
|
|
||||||
|
def memory_stats(self, device_index=None):
|
||||||
|
if hasattr(torch.cuda, 'memory_stats'):
|
||||||
|
return torch.cuda.memory_stats(device_index)
|
||||||
|
|
||||||
|
def reset_peak_memory_stats(self, device_index=None):
|
||||||
|
if hasattr(torch.cuda, 'reset_peak_memory_stats'):
|
||||||
|
return torch.cuda.reset_peak_memory_stats(device_index)
|
||||||
|
|
||||||
|
def memory_reserved(self, device_index=None):
|
||||||
|
if hasattr(torch.cuda, 'memory_reserved'):
|
||||||
|
return torch.cuda.memory_reserved(device_index)
|
||||||
|
|
||||||
|
def max_memory_reserved(self, device_index=None):
|
||||||
|
if hasattr(torch.cuda, 'max_memory_reserved'):
|
||||||
|
return torch.cuda.max_memory_reserved(device_index)
|
||||||
|
|
||||||
|
def total_memory(self, device_index=None):
|
||||||
|
return torch.cuda.get_device_properties(device_index).total_memory
|
||||||
|
|
||||||
|
def _get_nvml_gpu_id(self, torch_gpu_id):
|
||||||
|
"""
|
||||||
|
credit: https://discuss.pytorch.org/t/making-pynvml-match-torch-device-ids-cuda-visible-devices/103020
|
||||||
|
|
||||||
|
Remap torch device id to nvml device id, respecting CUDA_VISIBLE_DEVICES.
|
||||||
|
|
||||||
|
If the latter isn't set return the same id
|
||||||
|
"""
|
||||||
|
# if CUDA_VISIBLE_DEVICES is used automagically remap the id since pynvml ignores this env var
|
||||||
|
if "CUDA_VISIBLE_DEVICES" in os.environ:
|
||||||
|
ids = list(map(int, os.environ.get("CUDA_VISIBLE_DEVICES", "").split(",")))
|
||||||
|
return ids[torch_gpu_id] # remap
|
||||||
|
else:
|
||||||
|
return torch_gpu_id
|
||||||
|
|
||||||
|
def available_memory(self, device_index=None):
|
||||||
|
if pynvml:
|
||||||
|
if device_index is None:
|
||||||
|
device_index = self.current_device()
|
||||||
|
handle = pynvml.nvmlDeviceGetHandleByIndex(self._get_nvml_gpu_id(device_index))
|
||||||
|
info = pynvml.nvmlDeviceGetMemoryInfo(handle)
|
||||||
|
return info.free
|
||||||
|
else:
|
||||||
|
return self.total_memory(device_index) - self.memory_allocated(device_index)
|
||||||
|
|
||||||
|
# Data types
|
||||||
|
def is_bf16_supported(self):
|
||||||
|
if not torch.cuda.is_available():
|
||||||
|
return True
|
||||||
|
return torch.cuda.is_bf16_supported()
|
||||||
|
|
||||||
|
def is_fp16_supported(self):
|
||||||
|
if not torch.cuda.is_available():
|
||||||
|
return True
|
||||||
|
# See https://docs.nvidia.com/deeplearning/tensorrt/support-matrix/index.html#hardware-precision-matrix
|
||||||
|
# FP16 on compute capability 6.x is deprecated
|
||||||
|
allow_deprecated_fp16 = os.environ.get('DS_ALLOW_DEPRECATED_FP16', '0') == '1'
|
||||||
|
major, _ = torch.cuda.get_device_capability()
|
||||||
|
if major >= 7:
|
||||||
|
return True
|
||||||
|
elif major == 6 and allow_deprecated_fp16:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def supported_dtypes(self):
|
||||||
|
supported_dtypes = [torch.float]
|
||||||
|
if self.is_fp16_supported():
|
||||||
|
supported_dtypes.append(torch.half)
|
||||||
|
if self.is_bf16_supported():
|
||||||
|
supported_dtypes.append(torch.bfloat16)
|
||||||
|
return supported_dtypes
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
def is_available(self):
|
||||||
|
return torch.cuda.is_available()
|
||||||
|
|
||||||
|
def _get_nvtx_domain(self, domain):
|
||||||
|
if nvtx is None or domain is None:
|
||||||
|
return None
|
||||||
|
if domain not in self._nvtx_domains:
|
||||||
|
self._nvtx_domains[domain] = nvtx.get_domain(domain)
|
||||||
|
return self._nvtx_domains[domain]
|
||||||
|
|
||||||
|
def range_push(self, msg, domain=None, category=None):
|
||||||
|
nvtx_domain = self._get_nvtx_domain(domain)
|
||||||
|
if nvtx_domain is not None:
|
||||||
|
return nvtx_domain.push_range(message=msg, category=category)
|
||||||
|
torch_nvtx = getattr(torch.cuda, 'nvtx', None)
|
||||||
|
if torch_nvtx is not None and hasattr(torch_nvtx, 'range_push'):
|
||||||
|
return torch_nvtx.range_push(msg)
|
||||||
|
|
||||||
|
def range_pop(self, domain=None):
|
||||||
|
nvtx_domain = self._get_nvtx_domain(domain)
|
||||||
|
if nvtx_domain is not None:
|
||||||
|
return nvtx_domain.pop_range()
|
||||||
|
torch_nvtx = getattr(torch.cuda, 'nvtx', None)
|
||||||
|
if torch_nvtx is not None and hasattr(torch_nvtx, 'range_pop'):
|
||||||
|
return torch_nvtx.range_pop()
|
||||||
|
|
||||||
|
def lazy_call(self, callback):
|
||||||
|
return torch.cuda._lazy_call(callback)
|
||||||
|
|
||||||
|
def communication_backend_name(self):
|
||||||
|
return self._communication_backend_name
|
||||||
|
|
||||||
|
def is_triton_supported(self):
|
||||||
|
if not self.is_available():
|
||||||
|
return False
|
||||||
|
major, _ = torch.cuda.get_device_capability()
|
||||||
|
if major >= 8:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Graph operations
|
||||||
|
def create_graph(self):
|
||||||
|
return torch.cuda.CUDAGraph()
|
||||||
|
|
||||||
|
def capture_to_graph(self, graph, pool=None, stream=None):
|
||||||
|
return torch.cuda.graph(graph, pool, stream)
|
||||||
|
|
||||||
|
def replay_graph(self, graph):
|
||||||
|
graph.replay()
|
||||||
|
return
|
||||||
|
|
||||||
|
# Tensor operations
|
||||||
|
|
||||||
|
@property
|
||||||
|
def BFloat16Tensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.bfloat16, device='cuda')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ByteTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.uint8, device='cuda')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def DoubleTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.double, device='cuda')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def FloatTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.float, device='cuda')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def HalfTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.half, device='cuda')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def IntTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.int, device='cuda')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def LongTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.long, device='cuda')
|
||||||
|
|
||||||
|
def pin_memory(self, tensor, align_bytes=1):
|
||||||
|
return tensor.pin_memory()
|
||||||
|
|
||||||
|
def is_pinned(self, tensor):
|
||||||
|
return tensor.is_pinned()
|
||||||
|
|
||||||
|
def on_accelerator(self, tensor):
|
||||||
|
device_str = str(tensor.device)
|
||||||
|
if device_str.startswith('cuda:'):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def op_builder_dir(self):
|
||||||
|
try:
|
||||||
|
# is op_builder from deepspeed or a 3p version? this should only succeed if it's deepspeed
|
||||||
|
# if successful this also means we're doing a local install and not JIT compile path
|
||||||
|
from op_builder import __deepspeed__ # noqa: F401 # type: ignore
|
||||||
|
return "op_builder"
|
||||||
|
except ImportError:
|
||||||
|
return "deepspeed.ops.op_builder"
|
||||||
|
|
||||||
|
# dict that holds class name <--> class type mapping i.e.
|
||||||
|
# 'AsyncIOBuilder': <class 'op_builder.async_io.AsyncIOBuilder'>
|
||||||
|
# this dict will be filled at init stage
|
||||||
|
class_dict = None
|
||||||
|
|
||||||
|
def _lazy_init_class_dict(self):
|
||||||
|
if self.class_dict is not None:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
self.class_dict = {}
|
||||||
|
# begin initialize for create_op_builder()
|
||||||
|
# put all valid class name <--> class type mapping into class_dict
|
||||||
|
op_builder_dir = self.op_builder_dir()
|
||||||
|
op_builder_module = importlib.import_module(op_builder_dir)
|
||||||
|
op_builder_absolute_path = os.path.dirname(op_builder_module.__file__)
|
||||||
|
for _, module_name, _ in pkgutil.iter_modules([op_builder_absolute_path]):
|
||||||
|
# avoid self references,
|
||||||
|
# skip sub_directories which contains ops for other backend(cpu, npu, etc.).
|
||||||
|
if module_name != 'all_ops' and module_name != 'builder' and not os.path.isdir(
|
||||||
|
os.path.join(op_builder_absolute_path, module_name)):
|
||||||
|
module = importlib.import_module("{}.{}".format(op_builder_dir, module_name))
|
||||||
|
for member_name in module.__dir__():
|
||||||
|
if member_name.endswith(
|
||||||
|
'Builder'
|
||||||
|
) and member_name != "OpBuilder" and member_name != "CUDAOpBuilder" and member_name != "TorchCPUOpBuilder": # avoid abstract classes
|
||||||
|
if not member_name in self.class_dict:
|
||||||
|
self.class_dict[member_name] = getattr(module, member_name)
|
||||||
|
# end initialize for create_op_builder()
|
||||||
|
|
||||||
|
# create an instance of op builder and return, name specified by class_name
|
||||||
|
def create_op_builder(self, class_name):
|
||||||
|
self._lazy_init_class_dict()
|
||||||
|
if class_name in self.class_dict:
|
||||||
|
return self.class_dict[class_name]()
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# return an op builder class, name specified by class_name
|
||||||
|
def get_op_builder(self, class_name):
|
||||||
|
self._lazy_init_class_dict()
|
||||||
|
if class_name in self.class_dict:
|
||||||
|
return self.class_dict[class_name]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def build_extension(self):
|
||||||
|
from torch.utils.cpp_extension import BuildExtension
|
||||||
|
return BuildExtension
|
||||||
|
|
||||||
|
def export_envs(self):
|
||||||
|
return ['NCCL']
|
||||||
|
|
||||||
|
def visible_devices_envs(self):
|
||||||
|
return ['CUDA_VISIBLE_DEVICES']
|
||||||
|
|
||||||
|
def set_visible_devices_envs(self, current_env, local_accelerator_ids):
|
||||||
|
for env in self.visible_devices_envs():
|
||||||
|
current_env[env] = ",".join(map(str, local_accelerator_ids))
|
||||||
|
|
||||||
|
def get_compile_backend(self):
|
||||||
|
return self._compile_backend
|
||||||
|
|
||||||
|
def set_compile_backend(self, backend):
|
||||||
|
supported_backends = torch._dynamo.list_backends(exclude_tags=())
|
||||||
|
if backend in supported_backends:
|
||||||
|
self._compile_backend = backend
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
f"{backend} not supported by {self.device_name()}. Supported Backends are {supported_backends}")
|
||||||
@@ -0,0 +1,328 @@
|
|||||||
|
# Copyright (c) Microsoft Corporation.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
# DeepSpeed Team
|
||||||
|
|
||||||
|
import functools
|
||||||
|
import os
|
||||||
|
import pkgutil
|
||||||
|
import importlib
|
||||||
|
import torch
|
||||||
|
|
||||||
|
from .abstract_accelerator import DeepSpeedAccelerator
|
||||||
|
|
||||||
|
|
||||||
|
class HPU_Accelerator(DeepSpeedAccelerator):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._name = 'hpu'
|
||||||
|
self._communication_backend_name = 'hccl'
|
||||||
|
self._compile_backend = "hpu_backend"
|
||||||
|
self.apply_hpu_workarounds()
|
||||||
|
try:
|
||||||
|
import habana_frameworks.torch.hpu as hpu
|
||||||
|
self.hpu = hpu
|
||||||
|
torch.use_deterministic_algorithms(True)
|
||||||
|
# TODO: remove this WA when memory mapping break is resolved.
|
||||||
|
torch.utils.deterministic.fill_uninitialized_memory = False
|
||||||
|
except ImportError as e:
|
||||||
|
raise ValueError(
|
||||||
|
"HPU_Accelerator requires habana_frameworks.torch.hpu, which is not installed on this system.")
|
||||||
|
|
||||||
|
self.fp16_supported = None
|
||||||
|
|
||||||
|
def apply_hpu_workarounds(self):
|
||||||
|
|
||||||
|
def update_wa_env_var(key, value):
|
||||||
|
if key not in os.environ.keys():
|
||||||
|
os.environ[key] = value
|
||||||
|
|
||||||
|
update_wa_env_var("PT_HPU_LAZY_ACC_PAR_MODE", "0")
|
||||||
|
update_wa_env_var("PT_HPU_ENABLE_REFINE_DYNAMIC_SHAPES", "0")
|
||||||
|
|
||||||
|
# Device APIs
|
||||||
|
def is_synchronized_device(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def use_host_timers(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def resolves_data_dependency(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def handles_memory_backpressure(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def device_name(self, device_index=None):
|
||||||
|
# ignoring device_index.
|
||||||
|
return 'hpu'
|
||||||
|
|
||||||
|
def device(self, device_index=None):
|
||||||
|
return torch.device(self.device_name(device_index))
|
||||||
|
|
||||||
|
def set_device(self, device_index):
|
||||||
|
self.hpu.set_device(device_index)
|
||||||
|
|
||||||
|
def current_device(self):
|
||||||
|
return (self.hpu.current_device())
|
||||||
|
|
||||||
|
def current_device_name(self):
|
||||||
|
return 'hpu:{}'.format(self.current_device())
|
||||||
|
|
||||||
|
def device_count(self):
|
||||||
|
return self.hpu.device_count()
|
||||||
|
|
||||||
|
def synchronize(self, device_index=None):
|
||||||
|
return self.hpu.synchronize()
|
||||||
|
|
||||||
|
# RNG APIs
|
||||||
|
def random(self):
|
||||||
|
return torch.random
|
||||||
|
|
||||||
|
def set_rng_state(self, new_state, device_index=None):
|
||||||
|
self.hpu.random.set_rng_state(new_state)
|
||||||
|
|
||||||
|
def get_rng_state(self, device_index=None):
|
||||||
|
return self.hpu.random.get_rng_state()
|
||||||
|
|
||||||
|
def manual_seed(self, seed):
|
||||||
|
return self.hpu.random.manual_seed(seed)
|
||||||
|
|
||||||
|
def manual_seed_all(self, seed):
|
||||||
|
self.hpu.random.manual_seed_all(seed)
|
||||||
|
|
||||||
|
def initial_seed(self):
|
||||||
|
return self.hpu.random.initial_seed()
|
||||||
|
|
||||||
|
def default_generator(self, device_index):
|
||||||
|
return self.hpu.random.default_generators[device_index]
|
||||||
|
|
||||||
|
# Streams/Events
|
||||||
|
@property
|
||||||
|
def Stream(self):
|
||||||
|
return self.hpu.Stream
|
||||||
|
|
||||||
|
def stream(self, stream):
|
||||||
|
return self.hpu.stream(stream)
|
||||||
|
|
||||||
|
def current_stream(self, device_index=None):
|
||||||
|
return self.hpu.current_stream()
|
||||||
|
|
||||||
|
def default_stream(self, device_index=None):
|
||||||
|
return self.hpu.default_stream()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def Event(self):
|
||||||
|
import habana_frameworks.torch.core as htcore
|
||||||
|
return htcore.hpu.Event
|
||||||
|
|
||||||
|
# Memory management
|
||||||
|
def empty_cache(self):
|
||||||
|
return
|
||||||
|
|
||||||
|
def memory_allocated(self, device_index=None):
|
||||||
|
return self.hpu.memory_allocated()
|
||||||
|
|
||||||
|
def max_memory_allocated(self, device_index=None):
|
||||||
|
return self.hpu.max_memory_allocated()
|
||||||
|
|
||||||
|
def reset_max_memory_allocated(self, device_index=None):
|
||||||
|
return self.hpu.reset_max_memory_allocated()
|
||||||
|
|
||||||
|
def memory_cached(self, device_index=None):
|
||||||
|
return self.hpu.memory_cached(device_index)
|
||||||
|
|
||||||
|
def max_memory_cached(self, device_index=None):
|
||||||
|
return self.hpu.max_memory_cached(device_index)
|
||||||
|
|
||||||
|
def reset_max_memory_cached(self, device_index=None):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def memory_stats(self, device_index=None):
|
||||||
|
return self.hpu.memory_stats(device_index)
|
||||||
|
|
||||||
|
def reset_peak_memory_stats(self, device_index=None):
|
||||||
|
self.hpu.reset_peak_memory_stats(device_index)
|
||||||
|
|
||||||
|
def memory_reserved(self, device_index=None):
|
||||||
|
return self.hpu.memory_reserved(device_index)
|
||||||
|
|
||||||
|
def max_memory_reserved(self, device_index=None):
|
||||||
|
return self.hpu.max_memory_reserved(device_index)
|
||||||
|
|
||||||
|
def total_memory(self, device_index=None):
|
||||||
|
return self.memory_stats(device_index)['Limit']
|
||||||
|
|
||||||
|
def available_memory(self, device_index=None):
|
||||||
|
return self.total_memory(device_index) - self.memory_allocated(device_index)
|
||||||
|
|
||||||
|
# Data types
|
||||||
|
def is_bf16_supported(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def is_fp16_supported(self):
|
||||||
|
if self.fp16_supported is None:
|
||||||
|
import habana_frameworks.torch.utils.experimental as htexp
|
||||||
|
self.fp16_supported = htexp._is_fp16_supported()
|
||||||
|
return self.fp16_supported
|
||||||
|
|
||||||
|
def supported_dtypes(self):
|
||||||
|
supported_dtypes = [torch.float, torch.bfloat16]
|
||||||
|
if self.is_fp16_supported():
|
||||||
|
supported_dtypes.append(torch.half)
|
||||||
|
return supported_dtypes
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
def is_available(self):
|
||||||
|
return self.hpu.is_available()
|
||||||
|
|
||||||
|
def range_push(self, msg, domain=None, category=None):
|
||||||
|
return
|
||||||
|
|
||||||
|
def range_pop(self, domain=None):
|
||||||
|
return
|
||||||
|
|
||||||
|
def lazy_call(self, callback):
|
||||||
|
callback()
|
||||||
|
|
||||||
|
def communication_backend_name(self):
|
||||||
|
return self._communication_backend_name
|
||||||
|
|
||||||
|
def is_triton_supported(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Graph operations
|
||||||
|
def create_graph(self):
|
||||||
|
return self.hpu.HPUGraph()
|
||||||
|
|
||||||
|
def capture_to_graph(self, graph, pool=None, stream=None):
|
||||||
|
return self.hpu.graph(graph, stream=stream)
|
||||||
|
|
||||||
|
def replay_graph(self, graph):
|
||||||
|
graph.replay()
|
||||||
|
return
|
||||||
|
|
||||||
|
# Tensor operations
|
||||||
|
@property
|
||||||
|
def BFloat16Tensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.bfloat16, device='hpu')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ByteTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.uint8, device='hpu')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def DoubleTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.double, device='hpu')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def FloatTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.float, device='hpu')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def HalfTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.half, device='hpu')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def IntTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.int, device='hpu')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def LongTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.long, device='hpu')
|
||||||
|
|
||||||
|
def pin_memory(self, tensor, align_bytes=1):
|
||||||
|
return tensor.pin_memory(self.device())
|
||||||
|
|
||||||
|
def is_pinned(self, tensor):
|
||||||
|
return tensor.is_pinned()
|
||||||
|
|
||||||
|
def on_accelerator(self, tensor):
|
||||||
|
device_str = str(tensor.device)
|
||||||
|
if device_str.startswith('hpu:'):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def op_builder_dir(self):
|
||||||
|
try:
|
||||||
|
# is op_builder from deepspeed or a 3p version? this should only succeed if it's deepspeed
|
||||||
|
# if successful this also means we're doing a local install and not JIT compile path
|
||||||
|
from op_builder import __deepspeed__ # noqa: F401 # type: ignore
|
||||||
|
return "op_builder.hpu"
|
||||||
|
except ImportError:
|
||||||
|
return "deepspeed.ops.op_builder.hpu"
|
||||||
|
|
||||||
|
# dict that holds class name <--> class type mapping i.e.
|
||||||
|
# 'AsyncIOBuilder': <class 'op_builder.async_io.AsyncIOBuilder'>
|
||||||
|
# this dict will be filled at init stage
|
||||||
|
class_dict = None
|
||||||
|
|
||||||
|
def _lazy_init_class_dict(self):
|
||||||
|
if self.class_dict is not None:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
self.class_dict = {}
|
||||||
|
# begin initialize for create_op_builder()
|
||||||
|
# put all valid class name <--> class type mapping into class_dict
|
||||||
|
op_builder_dir = self.op_builder_dir()
|
||||||
|
op_builder_module = importlib.import_module(op_builder_dir)
|
||||||
|
op_builder_absolute_path = os.path.dirname(op_builder_module.__file__)
|
||||||
|
for _, module_name, _ in pkgutil.iter_modules([op_builder_absolute_path]):
|
||||||
|
# avoid self references,
|
||||||
|
# skip sub_directories which contains ops for other backend(cpu, npu, etc.).
|
||||||
|
if module_name != 'all_ops' and module_name != 'builder' and not os.path.isdir(
|
||||||
|
os.path.join(op_builder_absolute_path, module_name)):
|
||||||
|
module = importlib.import_module("{}.{}".format(op_builder_dir, module_name))
|
||||||
|
for member_name in module.__dir__():
|
||||||
|
if member_name.endswith(
|
||||||
|
'Builder'
|
||||||
|
) and member_name != "OpBuilder" and member_name != "CPUOpBuilder" and member_name != "TorchCPUOpBuilder": # avoid abstract classes
|
||||||
|
if not member_name in self.class_dict:
|
||||||
|
self.class_dict[member_name] = getattr(module, member_name)
|
||||||
|
# end initialize for create_op_builder()
|
||||||
|
|
||||||
|
# create an instance of op builder and return, name specified by class_name
|
||||||
|
def create_op_builder(self, class_name):
|
||||||
|
self._lazy_init_class_dict()
|
||||||
|
if class_name in self.class_dict:
|
||||||
|
return self.class_dict[class_name]()
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# return an op builder class, name specified by class_name
|
||||||
|
def get_op_builder(self, class_name):
|
||||||
|
self._lazy_init_class_dict()
|
||||||
|
if class_name in self.class_dict:
|
||||||
|
return self.class_dict[class_name]
|
||||||
|
else:
|
||||||
|
return self.class_dict['NotImplementedBuilder'] if 'NotImplementedBuilder' in self.class_dict else None
|
||||||
|
|
||||||
|
def build_extension(self):
|
||||||
|
from torch.utils.cpp_extension import BuildExtension
|
||||||
|
return BuildExtension
|
||||||
|
|
||||||
|
def export_envs(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def visible_devices_envs(self):
|
||||||
|
# Current way deepspeed set this env var is not applicable with all HPU instances
|
||||||
|
# User has to follow instructions in:
|
||||||
|
# https://docs.habana.ai/en/latest/PyTorch/Reference/PT_Multiple_Tenants_on_HPU/Multiple_Workloads_Single_Docker.html
|
||||||
|
# keeping CUDA_VISIBLE_DEVICES
|
||||||
|
return ['CUDA_VISIBLE_DEVICES'] #['HABANA_VISIBLE_MODULES']
|
||||||
|
|
||||||
|
def set_visible_devices_envs(self, current_env, local_accelerator_ids):
|
||||||
|
for env in self.visible_devices_envs():
|
||||||
|
current_env[env] = ",".join(map(str, local_accelerator_ids))
|
||||||
|
|
||||||
|
def get_compile_backend(self):
|
||||||
|
return self._compile_backend
|
||||||
|
|
||||||
|
def set_compile_backend(self, backend):
|
||||||
|
supported_backends = torch._dynamo.list_backends(exclude_tags=())
|
||||||
|
if backend in supported_backends:
|
||||||
|
self._compile_backend = backend
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
f"{backend} not supported by {self.device_name()}. Supported Backends are {supported_backends}")
|
||||||
@@ -0,0 +1,295 @@
|
|||||||
|
# Copyright (c) Microsoft Corporation.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
# DeepSpeed Team
|
||||||
|
import importlib
|
||||||
|
import inspect
|
||||||
|
import functools
|
||||||
|
|
||||||
|
from .abstract_accelerator import DeepSpeedAccelerator
|
||||||
|
import torch
|
||||||
|
# During setup stage torch may not be installed, pass on no torch will
|
||||||
|
# allow op builder related API to be executed.
|
||||||
|
|
||||||
|
|
||||||
|
class MLU_Accelerator(DeepSpeedAccelerator):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._name = 'mlu'
|
||||||
|
self._communication_backend_name = 'cncl'
|
||||||
|
self._compile_backend = "inductor"
|
||||||
|
self.class_dict = None
|
||||||
|
|
||||||
|
def is_synchronized_device(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def use_host_timers(self):
|
||||||
|
return self.is_synchronized_device()
|
||||||
|
|
||||||
|
def resolves_data_dependency(self):
|
||||||
|
return self.is_synchronized_device()
|
||||||
|
|
||||||
|
def handles_memory_backpressure(self):
|
||||||
|
return self.is_synchronized_device()
|
||||||
|
|
||||||
|
# Device APIs
|
||||||
|
def device_name(self, device_index=None):
|
||||||
|
if device_index == None:
|
||||||
|
return 'mlu'
|
||||||
|
return 'mlu:{}'.format(device_index)
|
||||||
|
|
||||||
|
def device(self, device_index=None):
|
||||||
|
return torch.mlu.device(device_index)
|
||||||
|
|
||||||
|
def set_device(self, device_index):
|
||||||
|
torch.mlu.set_device(device_index)
|
||||||
|
|
||||||
|
def current_device(self):
|
||||||
|
return torch.mlu.current_device()
|
||||||
|
|
||||||
|
def current_device_name(self):
|
||||||
|
return 'mlu:{}'.format(torch.mlu.current_device())
|
||||||
|
|
||||||
|
def device_count(self):
|
||||||
|
return torch.mlu.device_count()
|
||||||
|
|
||||||
|
def synchronize(self, device_index=None):
|
||||||
|
return torch.mlu.synchronize(device_index)
|
||||||
|
|
||||||
|
# RNG APIs
|
||||||
|
def random(self):
|
||||||
|
return torch.random
|
||||||
|
|
||||||
|
def set_rng_state(self, new_state, device_index=None):
|
||||||
|
if device_index is None:
|
||||||
|
return torch.mlu.set_rng_state(new_state)
|
||||||
|
|
||||||
|
return torch.mlu.set_rng_state(new_state, device_index)
|
||||||
|
|
||||||
|
def get_rng_state(self, device_index=None):
|
||||||
|
if device_index is None:
|
||||||
|
return torch.mlu.get_rng_state()
|
||||||
|
|
||||||
|
return torch.mlu.get_rng_state(device_index)
|
||||||
|
|
||||||
|
def manual_seed(self, seed):
|
||||||
|
return torch.mlu.manual_seed(seed)
|
||||||
|
|
||||||
|
def manual_seed_all(self, seed):
|
||||||
|
return torch.mlu.manual_seed_all(seed)
|
||||||
|
|
||||||
|
def initial_seed(self, seed):
|
||||||
|
return torch.mlu.initial_seed(seed)
|
||||||
|
|
||||||
|
def default_generator(self, device_index):
|
||||||
|
return torch.mlu.default_generators[device_index]
|
||||||
|
|
||||||
|
# Streams/Events
|
||||||
|
@property
|
||||||
|
def Stream(self):
|
||||||
|
return torch.mlu.Stream
|
||||||
|
|
||||||
|
def stream(self, stream):
|
||||||
|
return torch.mlu.stream(stream)
|
||||||
|
|
||||||
|
def current_stream(self, device_index=None):
|
||||||
|
return torch.mlu.current_stream(device_index)
|
||||||
|
|
||||||
|
def default_stream(self, device_index=None):
|
||||||
|
return torch.mlu.default_stream(device_index)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def Event(self):
|
||||||
|
return torch.mlu.Event
|
||||||
|
|
||||||
|
# Memory management
|
||||||
|
def empty_cache(self):
|
||||||
|
return torch.mlu.empty_cache()
|
||||||
|
|
||||||
|
def memory_allocated(self, device_index=None):
|
||||||
|
return torch.mlu.memory_allocated(device_index)
|
||||||
|
|
||||||
|
def max_memory_allocated(self, device_index=None):
|
||||||
|
return torch.mlu.max_memory_allocated(device_index)
|
||||||
|
|
||||||
|
def reset_max_memory_allocated(self, device_index=None):
|
||||||
|
return torch.mlu.reset_max_memory_allocated(device_index)
|
||||||
|
|
||||||
|
def memory_cached(self, device_index=None):
|
||||||
|
return torch.mlu.memory_cached(device_index)
|
||||||
|
|
||||||
|
def max_memory_cached(self, device_index=None):
|
||||||
|
return torch.mlu.max_memory_cached(device_index)
|
||||||
|
|
||||||
|
def reset_max_memory_cached(self, device_index=None):
|
||||||
|
return torch.mlu.reset_max_memory_cached(device_index)
|
||||||
|
|
||||||
|
def memory_stats(self, device_index=None):
|
||||||
|
if hasattr(torch.mlu, 'memory_stats'):
|
||||||
|
return torch.mlu.memory_stats(device_index)
|
||||||
|
|
||||||
|
def reset_peak_memory_stats(self, device_index=None):
|
||||||
|
if hasattr(torch.mlu, 'reset_peak_memory_stats'):
|
||||||
|
return torch.mlu.reset_peak_memory_stats(device_index)
|
||||||
|
|
||||||
|
def memory_reserved(self, device_index=None):
|
||||||
|
if hasattr(torch.mlu, 'memory_reserved'):
|
||||||
|
return torch.mlu.memory_reserved(device_index)
|
||||||
|
|
||||||
|
def max_memory_reserved(self, device_index=None):
|
||||||
|
if hasattr(torch.mlu, 'max_memory_reserved'):
|
||||||
|
return torch.mlu.max_memory_reserved(device_index)
|
||||||
|
|
||||||
|
def total_memory(self, device_index=None):
|
||||||
|
return torch.mlu.get_device_properties(device_index).total_memory
|
||||||
|
|
||||||
|
def available_memory(self, device_index=None):
|
||||||
|
return self.total_memory(device_index) - self.memory_allocated(device_index)
|
||||||
|
|
||||||
|
# Data types
|
||||||
|
def is_bf16_supported(self):
|
||||||
|
return torch.mlu.is_bf16_supported()
|
||||||
|
|
||||||
|
def is_fp16_supported(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def supported_dtypes(self):
|
||||||
|
supported_dtypes = [torch.float]
|
||||||
|
if self.is_fp16_supported():
|
||||||
|
supported_dtypes.append(torch.half)
|
||||||
|
if self.is_bf16_supported():
|
||||||
|
supported_dtypes.append(torch.bfloat16)
|
||||||
|
return supported_dtypes
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
def is_available(self):
|
||||||
|
return torch.mlu.is_available()
|
||||||
|
|
||||||
|
def range_push(self, msg, domain=None, category=None):
|
||||||
|
if hasattr(torch.mlu.cnpx, 'range_push'):
|
||||||
|
return torch.mlu.cnpx.range_push(msg)
|
||||||
|
|
||||||
|
def range_pop(self, domain=None):
|
||||||
|
if hasattr(torch.mlu.cnpx, 'range_pop'):
|
||||||
|
return torch.mlu.cnpx.range_pop()
|
||||||
|
|
||||||
|
def lazy_call(self, callback):
|
||||||
|
return torch.mlu._lazy_call(callback)
|
||||||
|
|
||||||
|
def communication_backend_name(self):
|
||||||
|
return self._communication_backend_name
|
||||||
|
|
||||||
|
def is_triton_supported(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Graph operations
|
||||||
|
def create_graph(self):
|
||||||
|
torch.mlu.MLUGraph()
|
||||||
|
|
||||||
|
def capture_to_graph(self, graph, pool=None, stream=None):
|
||||||
|
return torch.mlu.graph(graph, pool, stream)
|
||||||
|
|
||||||
|
def replay_graph(self, graph):
|
||||||
|
graph.replay()
|
||||||
|
return
|
||||||
|
|
||||||
|
# Tensor operations
|
||||||
|
|
||||||
|
@property
|
||||||
|
def BFloat16Tensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.bfloat16, device='mlu')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ByteTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.uint8, device='mlu')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def DoubleTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.double, device='mlu')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def FloatTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.float, device='mlu')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def HalfTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.half, device='mlu')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def IntTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.int, device='mlu')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def LongTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.long, device='mlu')
|
||||||
|
|
||||||
|
def pin_memory(self, tensor):
|
||||||
|
return tensor.pin_memory()
|
||||||
|
|
||||||
|
def is_pinned(self, tensor):
|
||||||
|
return tensor.is_pinned()
|
||||||
|
|
||||||
|
def on_accelerator(self, tensor):
|
||||||
|
device_str = str(tensor.device)
|
||||||
|
if device_str.startswith('mlu:'):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def op_builder_dir(self):
|
||||||
|
try:
|
||||||
|
# is op_builder from deepspeed or a 3p version? this should only succeed if it's deepspeed
|
||||||
|
# if successful this also means we're doing a local install and not JIT compile path
|
||||||
|
from op_builder import __deepspeed__ # noqa: F401 # type: ignore
|
||||||
|
return "op_builder.mlu"
|
||||||
|
except ImportError:
|
||||||
|
return "deepspeed.ops.op_builder.mlu"
|
||||||
|
|
||||||
|
def _lazy_init_class_dict(self):
|
||||||
|
if self.class_dict:
|
||||||
|
return
|
||||||
|
|
||||||
|
op_builder_module = importlib.import_module(self.op_builder_dir())
|
||||||
|
|
||||||
|
# get op builder class from op_builder/mlu/__init__.py
|
||||||
|
self.class_dict = {}
|
||||||
|
for class_name, class_obj in inspect.getmembers(op_builder_module, inspect.isclass):
|
||||||
|
self.class_dict[class_name] = class_obj
|
||||||
|
|
||||||
|
# create an instance of op builder and return, name specified by class_name
|
||||||
|
def create_op_builder(self, class_name):
|
||||||
|
builder_class = self.get_op_builder(class_name)
|
||||||
|
return builder_class()
|
||||||
|
|
||||||
|
# return an op builder class, name specified by class_name
|
||||||
|
def get_op_builder(self, class_name):
|
||||||
|
self._lazy_init_class_dict()
|
||||||
|
if class_name in self.class_dict:
|
||||||
|
return self.class_dict[class_name]
|
||||||
|
else:
|
||||||
|
return self.class_dict['NotImplementedBuilder']
|
||||||
|
|
||||||
|
def build_extension(self):
|
||||||
|
from torch.utils.cpp_extension import BuildExtension
|
||||||
|
return BuildExtension
|
||||||
|
|
||||||
|
def export_envs(self):
|
||||||
|
return ['NEUWARE_HOME', 'CNCL', 'LD_LIBRARY', 'PATH']
|
||||||
|
|
||||||
|
def visible_devices_envs(self):
|
||||||
|
return ['MLU_VISIBLE_DEVICES']
|
||||||
|
|
||||||
|
def set_visible_devices_envs(self, current_env, local_accelerator_ids):
|
||||||
|
for env in self.visible_devices_envs():
|
||||||
|
current_env[env] = ",".join(map(str, local_accelerator_ids))
|
||||||
|
|
||||||
|
def get_compile_backend(self):
|
||||||
|
return self._compile_backend
|
||||||
|
|
||||||
|
def set_compile_backend(self, backend):
|
||||||
|
supported_backends = torch._dynamo.list_backends(exclude_tags=())
|
||||||
|
if backend in supported_backends:
|
||||||
|
self._compile_backend = backend
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
f"{backend} not supported by {self.device_name()}. Supported Backends are {supported_backends }")
|
||||||
@@ -0,0 +1,279 @@
|
|||||||
|
# Copyright (c) Microsoft Corporation.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
# DeepSpeed Team
|
||||||
|
|
||||||
|
import torch
|
||||||
|
|
||||||
|
from .abstract_accelerator import DeepSpeedAccelerator
|
||||||
|
|
||||||
|
# During setup stage torch may not be installed, pass on no torch will
|
||||||
|
# allow op builder related API to be executed.
|
||||||
|
try:
|
||||||
|
import torch.mps
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class MPS_Accelerator(DeepSpeedAccelerator):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._name = "mps"
|
||||||
|
self._communication_backend_name = None
|
||||||
|
self._compile_backend = "inductor"
|
||||||
|
|
||||||
|
def is_synchronized_device(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def use_host_timers(self):
|
||||||
|
# Event timers are not supported on MPS
|
||||||
|
return True
|
||||||
|
|
||||||
|
def resolves_data_dependency(self):
|
||||||
|
return self.is_synchronized_device()
|
||||||
|
|
||||||
|
def handles_memory_backpressure(self):
|
||||||
|
return self.is_synchronized_device()
|
||||||
|
|
||||||
|
# Device APIs
|
||||||
|
def device_name(self, device_index=None):
|
||||||
|
if device_index is None:
|
||||||
|
return "mps"
|
||||||
|
return "mps:{}".format(device_index)
|
||||||
|
|
||||||
|
def device(self, device_index):
|
||||||
|
return torch.device("mps", index=0)
|
||||||
|
|
||||||
|
def set_device(self, device_index):
|
||||||
|
return
|
||||||
|
|
||||||
|
def current_device(self):
|
||||||
|
return torch.device("mps", index=0)
|
||||||
|
|
||||||
|
def current_device_name(self):
|
||||||
|
return "mps:0"
|
||||||
|
|
||||||
|
def device_count(self):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def synchronize(self, device_index=None):
|
||||||
|
return torch.mps.synchronize()
|
||||||
|
|
||||||
|
# RNG APIs
|
||||||
|
def random(self):
|
||||||
|
return torch.random
|
||||||
|
|
||||||
|
def set_rng_state(self, new_state, device_index=None):
|
||||||
|
return torch.mps.set_rng_state(new_state)
|
||||||
|
|
||||||
|
def get_rng_state(self, device_index=None):
|
||||||
|
return torch.mps.get_rng_state()
|
||||||
|
|
||||||
|
def manual_seed(self, seed):
|
||||||
|
return torch.mps.manual_seed(seed)
|
||||||
|
|
||||||
|
def manual_seed_all(self, seed):
|
||||||
|
return torch.mps.manual_seed(seed)
|
||||||
|
|
||||||
|
def seed(self):
|
||||||
|
return torch.mps.seed()
|
||||||
|
|
||||||
|
def initial_seed(self):
|
||||||
|
return
|
||||||
|
|
||||||
|
def default_generator(self, device_index):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Streams/Events
|
||||||
|
@property
|
||||||
|
def Stream(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def stream(self, stream):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def current_stream(self, device_index=None):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def default_stream(self, device_index=None):
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def Event(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Memory management
|
||||||
|
def empty_cache(self):
|
||||||
|
return torch.mps.empty_cache()
|
||||||
|
|
||||||
|
def memory_allocated(self, device_index=None):
|
||||||
|
return torch.mps.current_allocated_memory()
|
||||||
|
|
||||||
|
def max_memory_allocated(self, device_index=None):
|
||||||
|
return torch.mps.driver_allocated_memory()
|
||||||
|
|
||||||
|
def set_per_process_memory_fraction(self, fraction):
|
||||||
|
return torch.mps.set_per_process_memory_fraction(fraction)
|
||||||
|
|
||||||
|
def reset_max_memory_allocated(self, device_index=None):
|
||||||
|
return
|
||||||
|
|
||||||
|
def memory_cached(self, device_index=None):
|
||||||
|
return
|
||||||
|
|
||||||
|
def max_memory_cached(self, device_index=None):
|
||||||
|
return
|
||||||
|
|
||||||
|
def reset_max_memory_cached(self, device_index=None):
|
||||||
|
return
|
||||||
|
|
||||||
|
def memory_stats(self, device_index=None):
|
||||||
|
return
|
||||||
|
|
||||||
|
def reset_peak_memory_stats(self, device_index=None):
|
||||||
|
return
|
||||||
|
|
||||||
|
def memory_reserved(self, device_index=None):
|
||||||
|
return
|
||||||
|
|
||||||
|
def max_memory_reserved(self, device_index=None):
|
||||||
|
return
|
||||||
|
|
||||||
|
def total_memory(self, device_index=None):
|
||||||
|
return
|
||||||
|
|
||||||
|
def available_memory(self, device_index=None):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Data types
|
||||||
|
def is_bf16_supported(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def is_fp16_supported(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def supported_dtypes(self):
|
||||||
|
return [torch.float]
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
def is_available(self):
|
||||||
|
return hasattr(torch.backends, "mps") and torch.backends.mps.is_available()
|
||||||
|
|
||||||
|
def range_push(self, msg, domain=None, category=None):
|
||||||
|
return
|
||||||
|
|
||||||
|
def range_pop(self, domain=None):
|
||||||
|
return
|
||||||
|
|
||||||
|
def lazy_call(self, callback):
|
||||||
|
return
|
||||||
|
|
||||||
|
def communication_backend_name(self):
|
||||||
|
return self._communication_backend_name
|
||||||
|
|
||||||
|
def is_triton_supported(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Graph operations
|
||||||
|
def create_graph(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def capture_to_graph(self, graph, pool=None, stream=None):
|
||||||
|
from deepspeed.runtime.utils import noop_context
|
||||||
|
return noop_context()
|
||||||
|
|
||||||
|
def replay_graph(self, graph):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Tensor operations
|
||||||
|
@property
|
||||||
|
def BFloat16Tensor(self):
|
||||||
|
return
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ByteTensor(self):
|
||||||
|
return
|
||||||
|
|
||||||
|
@property
|
||||||
|
def DoubleTensor(self):
|
||||||
|
return
|
||||||
|
|
||||||
|
@property
|
||||||
|
def FloatTensor(self):
|
||||||
|
return
|
||||||
|
|
||||||
|
@property
|
||||||
|
def HalfTensor(self):
|
||||||
|
return
|
||||||
|
|
||||||
|
@property
|
||||||
|
def IntTensor(self):
|
||||||
|
return
|
||||||
|
|
||||||
|
@property
|
||||||
|
def LongTensor(self):
|
||||||
|
return
|
||||||
|
|
||||||
|
def pin_memory(self, tensor, align_bytes=1):
|
||||||
|
return tensor.pin_memory()
|
||||||
|
|
||||||
|
def is_pinned(self, tensor):
|
||||||
|
return tensor.is_pinned()
|
||||||
|
|
||||||
|
def on_accelerator(self, tensor):
|
||||||
|
device_str = str(tensor.device)
|
||||||
|
if device_str.startswith("mps"):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def op_builder_dir(self):
|
||||||
|
try:
|
||||||
|
# is op_builder from deepspeed or a 3p version? this should only succeed if it's deepspeed
|
||||||
|
# if successful this also means we're doing a local install and not JIT compile path
|
||||||
|
from op_builder import __deepspeed__ # noqa: F401 # type: ignore
|
||||||
|
|
||||||
|
return "op_builder"
|
||||||
|
except ImportError:
|
||||||
|
return "deepspeed.ops.op_builder"
|
||||||
|
|
||||||
|
# create an instance of op builder, specified by class_name
|
||||||
|
def create_op_builder(self, op_name):
|
||||||
|
builder_class = self.get_op_builder(op_name)
|
||||||
|
if builder_class is not None:
|
||||||
|
return builder_class()
|
||||||
|
return None
|
||||||
|
|
||||||
|
# return an op builder class, specified by class_name
|
||||||
|
def get_op_builder(self, class_name):
|
||||||
|
from deepspeed.ops.op_builder.cpu import NotImplementedBuilder
|
||||||
|
|
||||||
|
return NotImplementedBuilder
|
||||||
|
|
||||||
|
def build_extension(self):
|
||||||
|
from torch.utils.cpp_extension import BuildExtension
|
||||||
|
|
||||||
|
return BuildExtension
|
||||||
|
|
||||||
|
def export_envs(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
# TODO: mpu's visible envs is confirmed, keep as CUDA_VISIBLE_DEVICES
|
||||||
|
def visible_devices_envs(self):
|
||||||
|
# TODO: could not find visible devices env for mps
|
||||||
|
return ['CUDA_VISIBLE_DEVICES']
|
||||||
|
|
||||||
|
def set_visible_devices_envs(self, current_env, local_accelerator_ids):
|
||||||
|
for env in self.visible_devices_envs():
|
||||||
|
current_env[env] = ",".join(map(str, local_accelerator_ids))
|
||||||
|
|
||||||
|
def get_compile_backend(self):
|
||||||
|
return self._compile_backend
|
||||||
|
|
||||||
|
def set_compile_backend(self, backend):
|
||||||
|
supported_backends = torch._dynamo.list_backends(exclude_tags=())
|
||||||
|
if backend in supported_backends:
|
||||||
|
self._compile_backend = backend
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
f"{backend} not supported by {self.device_name()}. Supported Backends are {supported_backends}")
|
||||||
@@ -0,0 +1,294 @@
|
|||||||
|
# Copyright (c) Microsoft Corporation.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
# DeepSpeed Team
|
||||||
|
import importlib
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
from .abstract_accelerator import DeepSpeedAccelerator
|
||||||
|
# During setup stage torch may not be installed, pass on no torch will
|
||||||
|
# allow op builder related API to be executed.
|
||||||
|
try:
|
||||||
|
import torch.npu
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class NPU_Accelerator(DeepSpeedAccelerator):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self._name = 'npu'
|
||||||
|
self._communication_backend_name = 'hccl'
|
||||||
|
self._compile_backend = "inductor"
|
||||||
|
# dict that holds class name <--> class type mapping i.e.
|
||||||
|
# 'AsyncIOBuilder': <class 'op_builder.async_io.AsyncIOBuilder'>
|
||||||
|
# this dict will be filled at init stage
|
||||||
|
self.class_dict = None
|
||||||
|
|
||||||
|
def is_synchronized_device(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def use_host_timers(self):
|
||||||
|
return self.is_synchronized_device()
|
||||||
|
|
||||||
|
def resolves_data_dependency(self):
|
||||||
|
return self.is_synchronized_device()
|
||||||
|
|
||||||
|
def handles_memory_backpressure(self):
|
||||||
|
return self.is_synchronized_device()
|
||||||
|
|
||||||
|
# Device APIs
|
||||||
|
def device_name(self, device_index=None):
|
||||||
|
if device_index is None:
|
||||||
|
return 'npu'
|
||||||
|
return 'npu:{}'.format(device_index)
|
||||||
|
|
||||||
|
def device(self, device_index=None):
|
||||||
|
return torch.device('npu', device_index)
|
||||||
|
|
||||||
|
def set_device(self, device_index):
|
||||||
|
torch.npu.set_device(device_index)
|
||||||
|
|
||||||
|
def current_device(self):
|
||||||
|
return torch.npu.current_device()
|
||||||
|
|
||||||
|
def current_device_name(self):
|
||||||
|
return 'npu:{}'.format(torch.npu.current_device())
|
||||||
|
|
||||||
|
def device_count(self):
|
||||||
|
return torch.npu.device_count()
|
||||||
|
|
||||||
|
def synchronize(self, device_index=None):
|
||||||
|
return torch.npu.synchronize(device_index)
|
||||||
|
|
||||||
|
# RNG APIs
|
||||||
|
def random(self):
|
||||||
|
return torch.random
|
||||||
|
|
||||||
|
def set_rng_state(self, new_state, device_index=None):
|
||||||
|
if device_index is None:
|
||||||
|
return torch.npu.set_rng_state(new_state)
|
||||||
|
|
||||||
|
return torch.npu.set_rng_state(new_state, device_index)
|
||||||
|
|
||||||
|
def get_rng_state(self, device_index=None):
|
||||||
|
if device_index is None:
|
||||||
|
return torch.npu.get_rng_state()
|
||||||
|
|
||||||
|
return torch.npu.get_rng_state(device_index)
|
||||||
|
|
||||||
|
def manual_seed(self, seed):
|
||||||
|
return torch.npu.manual_seed(seed)
|
||||||
|
|
||||||
|
def manual_seed_all(self, seed):
|
||||||
|
return torch.npu.manual_seed_all(seed)
|
||||||
|
|
||||||
|
def initial_seed(self):
|
||||||
|
return torch.npu.initial_seed()
|
||||||
|
|
||||||
|
def default_generator(self, device_index):
|
||||||
|
return torch.npu.default_generators[device_index]
|
||||||
|
|
||||||
|
# Streams/Events
|
||||||
|
@property
|
||||||
|
def Stream(self):
|
||||||
|
return torch.npu.Stream
|
||||||
|
|
||||||
|
def stream(self, stream):
|
||||||
|
return torch.npu.stream(stream)
|
||||||
|
|
||||||
|
def current_stream(self, device_index=None):
|
||||||
|
return torch.npu.current_stream(device_index)
|
||||||
|
|
||||||
|
def default_stream(self, device_index=None):
|
||||||
|
return torch.npu.default_stream(device_index)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def Event(self):
|
||||||
|
return torch.npu.Event
|
||||||
|
|
||||||
|
# Memory management
|
||||||
|
def empty_cache(self):
|
||||||
|
return torch.npu.empty_cache()
|
||||||
|
|
||||||
|
def memory_allocated(self, device_index=None):
|
||||||
|
return torch.npu.memory_allocated(device_index)
|
||||||
|
|
||||||
|
def max_memory_allocated(self, device_index=None):
|
||||||
|
return torch.npu.max_memory_allocated(device_index)
|
||||||
|
|
||||||
|
def reset_max_memory_allocated(self, device_index=None):
|
||||||
|
return torch.npu.reset_max_memory_allocated(device_index)
|
||||||
|
|
||||||
|
def memory_cached(self, device_index=None):
|
||||||
|
return torch.npu.memory_cached(device_index)
|
||||||
|
|
||||||
|
def max_memory_cached(self, device_index=None):
|
||||||
|
return torch.npu.max_memory_cached(device_index)
|
||||||
|
|
||||||
|
def reset_max_memory_cached(self, device_index=None):
|
||||||
|
return torch.npu.reset_max_memory_cached(device_index)
|
||||||
|
|
||||||
|
def memory_stats(self, device_index=None):
|
||||||
|
if hasattr(torch.npu, 'memory_stats'):
|
||||||
|
return torch.npu.memory_stats(device_index)
|
||||||
|
|
||||||
|
def reset_peak_memory_stats(self, device_index=None):
|
||||||
|
if hasattr(torch.npu, 'reset_peak_memory_stats'):
|
||||||
|
return torch.npu.reset_peak_memory_stats(device_index)
|
||||||
|
|
||||||
|
def memory_reserved(self, device_index=None):
|
||||||
|
if hasattr(torch.npu, 'memory_reserved'):
|
||||||
|
return torch.npu.memory_reserved(device_index)
|
||||||
|
|
||||||
|
def max_memory_reserved(self, device_index=None):
|
||||||
|
if hasattr(torch.npu, 'max_memory_reserved'):
|
||||||
|
return torch.npu.max_memory_reserved(device_index)
|
||||||
|
|
||||||
|
def total_memory(self, device_index=None):
|
||||||
|
return torch.npu.get_device_properties(device_index).total_memory
|
||||||
|
|
||||||
|
def available_memory(self, device_index=None):
|
||||||
|
return self.total_memory(device_index) - self.memory_allocated(device_index)
|
||||||
|
|
||||||
|
# Data types
|
||||||
|
def is_bf16_supported(self):
|
||||||
|
return torch.npu.is_bf16_supported()
|
||||||
|
|
||||||
|
def is_fp16_supported(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def supported_dtypes(self):
|
||||||
|
return [torch.float, torch.half, torch.bfloat16]
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
def is_available(self):
|
||||||
|
return torch.npu.is_available()
|
||||||
|
|
||||||
|
def range_push(self, msg, domain=None, category=None):
|
||||||
|
return
|
||||||
|
|
||||||
|
def range_pop(self, domain=None):
|
||||||
|
return
|
||||||
|
|
||||||
|
def lazy_call(self, callback):
|
||||||
|
return torch.npu._lazy_call(callback)
|
||||||
|
|
||||||
|
def communication_backend_name(self):
|
||||||
|
return self._communication_backend_name
|
||||||
|
|
||||||
|
def is_triton_supported(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Graph operations
|
||||||
|
def create_graph(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def capture_to_graph(self, graph, pool=None, stream=None):
|
||||||
|
from deepspeed.runtime.utils import noop_context
|
||||||
|
return noop_context()
|
||||||
|
|
||||||
|
def replay_graph(self, graph):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Tensor operations
|
||||||
|
|
||||||
|
@property
|
||||||
|
def BFloat16Tensor(self):
|
||||||
|
return torch.npu.BFloat16Tensor
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ByteTensor(self):
|
||||||
|
return torch.npu.ByteTensor
|
||||||
|
|
||||||
|
@property
|
||||||
|
def DoubleTensor(self):
|
||||||
|
return torch.npu.DoubleTensor
|
||||||
|
|
||||||
|
@property
|
||||||
|
def FloatTensor(self):
|
||||||
|
return torch.npu.FloatTensor
|
||||||
|
|
||||||
|
@property
|
||||||
|
def HalfTensor(self):
|
||||||
|
return torch.npu.HalfTensor
|
||||||
|
|
||||||
|
@property
|
||||||
|
def IntTensor(self):
|
||||||
|
return torch.npu.IntTensor
|
||||||
|
|
||||||
|
@property
|
||||||
|
def LongTensor(self):
|
||||||
|
return torch.npu.LongTensor
|
||||||
|
|
||||||
|
def pin_memory(self, tensor, align_bytes=1):
|
||||||
|
return tensor.pin_memory()
|
||||||
|
|
||||||
|
def is_pinned(self, tensor):
|
||||||
|
return tensor.is_pinned()
|
||||||
|
|
||||||
|
def on_accelerator(self, tensor):
|
||||||
|
device_str = str(tensor.device)
|
||||||
|
if device_str.startswith('npu:'):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def op_builder_dir(self):
|
||||||
|
try:
|
||||||
|
# is op_builder from deepspeed or a 3p version? this should only succeed if it's deepspeed
|
||||||
|
# if successful this also means we're doing a local install and not JIT compile path
|
||||||
|
from op_builder import __deepspeed__ # noqa: F401 # type: ignore
|
||||||
|
return "op_builder.npu"
|
||||||
|
except ImportError:
|
||||||
|
return "deepspeed.ops.op_builder.npu"
|
||||||
|
|
||||||
|
def _lazy_init_class_dict(self):
|
||||||
|
if self.class_dict:
|
||||||
|
return
|
||||||
|
|
||||||
|
op_builder_module = importlib.import_module(self.op_builder_dir())
|
||||||
|
|
||||||
|
# get op builder class from op_builder/npu/__init__.py
|
||||||
|
self.class_dict = {}
|
||||||
|
for class_name, class_obj in inspect.getmembers(op_builder_module, inspect.isclass):
|
||||||
|
self.class_dict[class_name] = class_obj
|
||||||
|
|
||||||
|
# create an instance of op builder and return, name specified by class_name
|
||||||
|
def create_op_builder(self, class_name):
|
||||||
|
builder_class = self.get_op_builder(class_name)
|
||||||
|
return None if builder_class is None else builder_class()
|
||||||
|
|
||||||
|
# return an op builder class, name specified by class_name
|
||||||
|
def get_op_builder(self, class_name):
|
||||||
|
self._lazy_init_class_dict()
|
||||||
|
if class_name in self.class_dict:
|
||||||
|
return self.class_dict[class_name]
|
||||||
|
else:
|
||||||
|
return self.class_dict['NotImplementedBuilder'] if 'NotImplementedBuilder' in self.class_dict else None
|
||||||
|
|
||||||
|
def build_extension(self):
|
||||||
|
from torch.utils.cpp_extension import BuildExtension
|
||||||
|
return BuildExtension
|
||||||
|
|
||||||
|
def export_envs(self):
|
||||||
|
return ['ASCEND', 'HCCL', 'LD_LIBRARY', 'PATH']
|
||||||
|
|
||||||
|
def visible_devices_envs(self):
|
||||||
|
return ['ASCEND_RT_VISIBLE_DEVICES']
|
||||||
|
|
||||||
|
def set_visible_devices_envs(self, current_env, local_accelerator_ids):
|
||||||
|
for env in self.visible_devices_envs():
|
||||||
|
current_env[env] = ",".join(map(str, local_accelerator_ids))
|
||||||
|
|
||||||
|
def get_compile_backend(self):
|
||||||
|
return self._compile_backend
|
||||||
|
|
||||||
|
def set_compile_backend(self, backend):
|
||||||
|
supported_backends = torch._dynamo.list_backends(exclude_tags=())
|
||||||
|
if backend in supported_backends:
|
||||||
|
self._compile_backend = backend
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
f"{backend} not supported by {self.device_name()}. Supported Backends are {supported_backends }")
|
||||||
@@ -0,0 +1,299 @@
|
|||||||
|
# Copyright (c) Microsoft Corporation.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
# DeepSpeed Team
|
||||||
|
import os
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Importing logger currently requires that torch is installed, hence the try...except
|
||||||
|
# TODO: Remove logger dependency on torch.
|
||||||
|
from deepspeed.utils import logger as accel_logger
|
||||||
|
except ImportError as e:
|
||||||
|
accel_logger = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
from accelerator.abstract_accelerator import DeepSpeedAccelerator as dsa1
|
||||||
|
except ImportError as e:
|
||||||
|
dsa1 = None
|
||||||
|
try:
|
||||||
|
from deepspeed.accelerator.abstract_accelerator import DeepSpeedAccelerator as dsa2
|
||||||
|
except ImportError as e:
|
||||||
|
dsa2 = None
|
||||||
|
|
||||||
|
SUPPORTED_ACCELERATOR_LIST = ['cuda', 'cpu', 'xpu', 'npu', 'mps', 'hpu', 'mlu', 'sdaa', 'supa']
|
||||||
|
|
||||||
|
ds_accelerator = None
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_accelerator(accel_obj):
|
||||||
|
# because abstract_accelerator has different path during
|
||||||
|
# build time (accelerator.abstract_accelerator)
|
||||||
|
# and run time (deepspeed.accelerator.abstract_accelerator)
|
||||||
|
# and extension would import the
|
||||||
|
# run time abstract_accelerator/DeepSpeedAccelerator as its base
|
||||||
|
# class, so we need to compare accel_obj with both base class.
|
||||||
|
# if accel_obj is instance of DeepSpeedAccelerator in one of
|
||||||
|
# accelerator.abstractor_accelerator
|
||||||
|
# or deepspeed.accelerator.abstract_accelerator, consider accel_obj
|
||||||
|
# is a conforming object
|
||||||
|
if not ((dsa1 is not None and isinstance(accel_obj, dsa1)) or (dsa2 is not None and isinstance(accel_obj, dsa2))):
|
||||||
|
raise AssertionError(f"{accel_obj.__class__.__name__} accelerator is not subclass of DeepSpeedAccelerator")
|
||||||
|
|
||||||
|
# TODO: turn off is_available test since this breaks tests
|
||||||
|
# assert accel_obj.is_available(), \
|
||||||
|
# f'{accel_obj.__class__.__name__} accelerator fails is_available() test'
|
||||||
|
|
||||||
|
|
||||||
|
def is_current_accelerator_supported():
|
||||||
|
return get_accelerator().device_name() in SUPPORTED_ACCELERATOR_LIST
|
||||||
|
|
||||||
|
|
||||||
|
def get_accelerator():
|
||||||
|
global ds_accelerator
|
||||||
|
if ds_accelerator is not None:
|
||||||
|
return ds_accelerator
|
||||||
|
|
||||||
|
accelerator_name = None
|
||||||
|
ds_set_method = None
|
||||||
|
# 1. Detect whether there is override of DeepSpeed accelerators from environment variable.
|
||||||
|
if "DS_ACCELERATOR" in os.environ.keys():
|
||||||
|
accelerator_name = os.environ["DS_ACCELERATOR"]
|
||||||
|
if accelerator_name == "xpu":
|
||||||
|
try:
|
||||||
|
import torch
|
||||||
|
assert hasattr(torch, 'xpu') and torch.xpu.is_available(), \
|
||||||
|
"XPU_Accelerator requires PyTorch with XPU support (torch.xpu)."
|
||||||
|
except (ImportError, AssertionError) as e:
|
||||||
|
raise ValueError(f"XPU_Accelerator requires PyTorch with XPU support: {e}")
|
||||||
|
elif accelerator_name == "cpu":
|
||||||
|
pass
|
||||||
|
elif accelerator_name == "npu":
|
||||||
|
try:
|
||||||
|
import torch_npu # noqa: F401 # type: ignore
|
||||||
|
except ImportError as e:
|
||||||
|
raise ValueError("NPU_Accelerator requires torch_npu, which is not installed on this system.")
|
||||||
|
pass
|
||||||
|
elif accelerator_name == "sdaa":
|
||||||
|
try:
|
||||||
|
import torch_sdaa # noqa: F401 # type: ignore
|
||||||
|
except ImportError as e:
|
||||||
|
raise ValueError("SDAA_Accelerator requires torch_sdaa, which is not installed on this system.")
|
||||||
|
pass
|
||||||
|
elif accelerator_name == "mps":
|
||||||
|
try:
|
||||||
|
import torch.mps
|
||||||
|
|
||||||
|
# should use torch.mps.is_available() if it exists someday but this is used as proxy
|
||||||
|
torch.mps.current_allocated_memory()
|
||||||
|
except (RuntimeError, ImportError) as e:
|
||||||
|
raise ValueError("MPS_Accelerator requires torch.mps, which is not installed on this system.")
|
||||||
|
elif accelerator_name == "hpu":
|
||||||
|
try:
|
||||||
|
import habana_frameworks.torch.hpu # noqa: F401
|
||||||
|
except ImportError as e:
|
||||||
|
raise ValueError(
|
||||||
|
"HPU_Accelerator requires habana_frameworks.torch.hpu, which is not installed on this system.")
|
||||||
|
elif accelerator_name == "mlu":
|
||||||
|
try:
|
||||||
|
import torch_mlu # noqa: F401
|
||||||
|
except ImportError as e:
|
||||||
|
raise ValueError("MLU_Accelerator requires torch_mlu, which is not installed on this system.")
|
||||||
|
elif accelerator_name == "supa":
|
||||||
|
try:
|
||||||
|
import torch_supa # noqa: F401 # type: ignore
|
||||||
|
except ImportError as e:
|
||||||
|
raise ValueError("SUPA_Accelerator requires torch_supa, which is not installed on this system.")
|
||||||
|
elif accelerator_name not in SUPPORTED_ACCELERATOR_LIST:
|
||||||
|
raise ValueError(f'DS_ACCELERATOR must be one of {SUPPORTED_ACCELERATOR_LIST}. '
|
||||||
|
f'Value "{accelerator_name}" is not supported')
|
||||||
|
ds_set_method = "override"
|
||||||
|
|
||||||
|
# 2. If no override, detect which accelerator to use automatically
|
||||||
|
if accelerator_name is None:
|
||||||
|
# We need a way to choose among different accelerator types.
|
||||||
|
# Currently we detect which accelerator extension is installed
|
||||||
|
# in the environment and use it if the installing answer is True.
|
||||||
|
# An alternative might be detect whether CUDA device is installed on
|
||||||
|
# the system but this comes with two pitfalls:
|
||||||
|
# 1. the system may not have torch pre-installed, so
|
||||||
|
# get_accelerator().is_available() may not work.
|
||||||
|
# 2. Some scenario like install on login node (without CUDA device)
|
||||||
|
# and run on compute node (with CUDA device) may cause mismatch
|
||||||
|
# between installation time and runtime.
|
||||||
|
|
||||||
|
try:
|
||||||
|
import torch
|
||||||
|
|
||||||
|
# Detect XPU via PyTorch
|
||||||
|
if hasattr(torch, 'xpu'):
|
||||||
|
if torch.xpu.is_available():
|
||||||
|
accelerator_name = "xpu"
|
||||||
|
except ImportError as e:
|
||||||
|
pass
|
||||||
|
if accelerator_name is None:
|
||||||
|
try:
|
||||||
|
import torch_npu # noqa: F401,F811 # type: ignore
|
||||||
|
|
||||||
|
accelerator_name = "npu"
|
||||||
|
except ImportError as e:
|
||||||
|
pass
|
||||||
|
if accelerator_name is None:
|
||||||
|
try:
|
||||||
|
import torch_sdaa # noqa: F401,F811 # type: ignore
|
||||||
|
|
||||||
|
accelerator_name = "sdaa"
|
||||||
|
except ImportError as e:
|
||||||
|
pass
|
||||||
|
if accelerator_name is None:
|
||||||
|
try:
|
||||||
|
import torch.mps
|
||||||
|
|
||||||
|
# should use torch.mps.is_available() if it exists someday but this is used as proxy
|
||||||
|
torch.mps.current_allocated_memory()
|
||||||
|
accelerator_name = "mps"
|
||||||
|
except (RuntimeError, ImportError) as e:
|
||||||
|
pass
|
||||||
|
if accelerator_name is None:
|
||||||
|
try:
|
||||||
|
import habana_frameworks.torch.hpu # noqa: F401,F811
|
||||||
|
|
||||||
|
accelerator_name = "hpu"
|
||||||
|
except ImportError as e:
|
||||||
|
pass
|
||||||
|
if accelerator_name is None:
|
||||||
|
try:
|
||||||
|
import torch_mlu # noqa: F401,F811
|
||||||
|
|
||||||
|
accelerator_name = "mlu"
|
||||||
|
except ImportError as e:
|
||||||
|
pass
|
||||||
|
if accelerator_name is None:
|
||||||
|
try:
|
||||||
|
# Detect Biren SUPA GPU. torch_supa spoofs torch.cuda so this #ignore-cuda
|
||||||
|
# check must come before the CUDA detection below.
|
||||||
|
import torch_supa # noqa: F401,F811 # type: ignore
|
||||||
|
import torch
|
||||||
|
|
||||||
|
if hasattr(torch, 'supa') and torch.supa.is_available():
|
||||||
|
accelerator_name = "supa"
|
||||||
|
except ImportError as e:
|
||||||
|
pass
|
||||||
|
if accelerator_name is None:
|
||||||
|
try:
|
||||||
|
import torch
|
||||||
|
|
||||||
|
# Determine if we are on a GPU or x86 CPU with torch.
|
||||||
|
# "torch.cuda.is_available()" provides a stronger guarantee, #ignore-cuda
|
||||||
|
# ensuring that we are free from CUDA initialization errors.
|
||||||
|
# While "torch.cuda.device_count() > 0" check ensures that #ignore-cuda
|
||||||
|
# we won't try to do any CUDA calls when no device is available
|
||||||
|
# For reference: https://github.com/deepspeedai/DeepSpeed/pull/6810
|
||||||
|
if torch.cuda.device_count() > 0 and torch.cuda.is_available(): #ignore-cuda
|
||||||
|
accelerator_name = "cuda"
|
||||||
|
except (RuntimeError, ImportError) as e:
|
||||||
|
# TODO need a more decent way to detect which accelerator to use, consider using nvidia-smi command for detection
|
||||||
|
pass
|
||||||
|
if accelerator_name is None:
|
||||||
|
# borrow this log from PR#5084
|
||||||
|
if accel_logger is not None:
|
||||||
|
accel_logger.warning(
|
||||||
|
"Setting accelerator to CPU. If you have GPU or other accelerator, we were unable to detect it.")
|
||||||
|
# cpu added as catch-all when accelerator detection fails
|
||||||
|
accelerator_name = "cpu"
|
||||||
|
|
||||||
|
ds_set_method = "auto detect"
|
||||||
|
|
||||||
|
# 3. Set ds_accelerator accordingly
|
||||||
|
if accelerator_name == "cuda":
|
||||||
|
from .cuda_accelerator import CUDA_Accelerator
|
||||||
|
|
||||||
|
ds_accelerator = CUDA_Accelerator()
|
||||||
|
elif accelerator_name == "cpu":
|
||||||
|
from .cpu_accelerator import CPU_Accelerator
|
||||||
|
|
||||||
|
ds_accelerator = CPU_Accelerator()
|
||||||
|
elif accelerator_name == "xpu":
|
||||||
|
from .xpu_accelerator import XPU_Accelerator
|
||||||
|
|
||||||
|
ds_accelerator = XPU_Accelerator()
|
||||||
|
elif accelerator_name == "npu":
|
||||||
|
from .npu_accelerator import NPU_Accelerator
|
||||||
|
|
||||||
|
ds_accelerator = NPU_Accelerator()
|
||||||
|
elif accelerator_name == "sdaa":
|
||||||
|
from .sdaa_accelerator import SDAA_Accelerator
|
||||||
|
|
||||||
|
ds_accelerator = SDAA_Accelerator()
|
||||||
|
elif accelerator_name == "mps":
|
||||||
|
from .mps_accelerator import MPS_Accelerator
|
||||||
|
|
||||||
|
ds_accelerator = MPS_Accelerator()
|
||||||
|
elif accelerator_name == 'hpu':
|
||||||
|
from .hpu_accelerator import HPU_Accelerator
|
||||||
|
|
||||||
|
ds_accelerator = HPU_Accelerator()
|
||||||
|
elif accelerator_name == 'mlu':
|
||||||
|
from .mlu_accelerator import MLU_Accelerator
|
||||||
|
|
||||||
|
ds_accelerator = MLU_Accelerator()
|
||||||
|
elif accelerator_name == 'supa':
|
||||||
|
from .supa_accelerator import SUPA_Accelerator
|
||||||
|
|
||||||
|
ds_accelerator = SUPA_Accelerator()
|
||||||
|
_validate_accelerator(ds_accelerator)
|
||||||
|
if accel_logger is not None:
|
||||||
|
accel_logger.info(f"Setting ds_accelerator to {ds_accelerator._name} ({ds_set_method})")
|
||||||
|
return ds_accelerator
|
||||||
|
|
||||||
|
|
||||||
|
def set_accelerator(accel_obj):
|
||||||
|
global ds_accelerator
|
||||||
|
_validate_accelerator(accel_obj)
|
||||||
|
if accel_logger is not None and accel_obj is not None:
|
||||||
|
accel_logger.info(f"Setting ds_accelerator to {accel_obj._name} (model specified)")
|
||||||
|
ds_accelerator = accel_obj
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
-----------[code] test_get.py -----------
|
||||||
|
from deepspeed.accelerator import get_accelerator
|
||||||
|
my_accelerator = get_accelerator()
|
||||||
|
logger.info(f'{my_accelerator._name=}')
|
||||||
|
logger.info(f'{my_accelerator._communication_backend=}')
|
||||||
|
logger.info(f'{my_accelerator.HalfTensor().device=}')
|
||||||
|
logger.info(f'{my_accelerator.total_memory()=}')
|
||||||
|
-----------[code] test_get.py -----------
|
||||||
|
|
||||||
|
---[output] python test_get.py---------
|
||||||
|
my_accelerator.name()='cuda'
|
||||||
|
my_accelerator.communication_backend='nccl'
|
||||||
|
my_accelerator.HalfTensor().device=device(type='cuda', index=0)
|
||||||
|
my_accelerator.total_memory()=34089730048
|
||||||
|
---[output] python test_get.py---------
|
||||||
|
|
||||||
|
**************************************************************************
|
||||||
|
-----------[code] test_set.py -----------
|
||||||
|
from deepspeed.accelerator.cuda_accelerator import CUDA_Accelerator
|
||||||
|
cu_accel = CUDA_Accelerator()
|
||||||
|
logger.info(f'{id(cu_accel)=}')
|
||||||
|
from deepspeed.accelerator import set_accelerator, get_accelerator
|
||||||
|
set_accelerator(cu_accel)
|
||||||
|
|
||||||
|
my_accelerator = get_accelerator()
|
||||||
|
logger.info(f'{id(my_accelerator)=}')
|
||||||
|
logger.info(f'{my_accelerator._name=}')
|
||||||
|
logger.info(f'{my_accelerator._communication_backend=}')
|
||||||
|
logger.info(f'{my_accelerator.HalfTensor().device=}')
|
||||||
|
logger.info(f'{my_accelerator.total_memory()=}')
|
||||||
|
-----------[code] test_set.py -----------
|
||||||
|
|
||||||
|
|
||||||
|
---[output] python test_set.py---------
|
||||||
|
id(cu_accel)=139648165478304
|
||||||
|
my_accelerator=<deepspeed.accelerator.cuda_accelerator.CUDA_Accelerator object at 0x7f025f4bffa0>
|
||||||
|
my_accelerator.name='cuda'
|
||||||
|
my_accelerator.communication_backend='nccl'
|
||||||
|
my_accelerator.HalfTensor().device=device(type='cuda', index=0)
|
||||||
|
my_accelerator.total_memory()=34089730048
|
||||||
|
---[output] python test_set.py---------
|
||||||
|
"""
|
||||||
@@ -0,0 +1,323 @@
|
|||||||
|
# Copyright (c) Microsoft Corporation.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
# BSD 3- Clause License Copyright (c) 2023, Tecorigin Co., Ltd. All rights
|
||||||
|
# reserved.
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are met:
|
||||||
|
# Redistributions of source code must retain the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer.
|
||||||
|
# Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
# Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
# may be used to endorse or promote products derived from this software
|
||||||
|
# without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
# INTERRUPTION)
|
||||||
|
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
# STRICT LIABILITY,OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
|
||||||
|
# WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||||
|
# OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
# DeepSpeed Team
|
||||||
|
|
||||||
|
import importlib
|
||||||
|
import inspect
|
||||||
|
import functools
|
||||||
|
|
||||||
|
from .abstract_accelerator import DeepSpeedAccelerator
|
||||||
|
# During setup stage torch may not be installed, pass on no torch will
|
||||||
|
# allow op builder related API to be executed.
|
||||||
|
try:
|
||||||
|
import torch.sdaa
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class SDAA_Accelerator(DeepSpeedAccelerator):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._name = 'sdaa'
|
||||||
|
self._communication_backend_name = 'tccl'
|
||||||
|
self._compile_backend = "inductor"
|
||||||
|
self.class_dict = None
|
||||||
|
|
||||||
|
def is_synchronized_device(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def use_host_timers(self):
|
||||||
|
return self.is_synchronized_device()
|
||||||
|
|
||||||
|
def resolves_data_dependency(self):
|
||||||
|
return self.is_synchronized_device()
|
||||||
|
|
||||||
|
def handles_memory_backpressure(self):
|
||||||
|
return self.is_synchronized_device()
|
||||||
|
|
||||||
|
# Device APIs
|
||||||
|
def device_name(self, device_index=None):
|
||||||
|
if device_index is None:
|
||||||
|
return 'sdaa'
|
||||||
|
return 'sdaa:{}'.format(device_index)
|
||||||
|
|
||||||
|
def device(self, device_index=None):
|
||||||
|
return torch.sdaa.device(device_index)
|
||||||
|
|
||||||
|
def set_device(self, device_index):
|
||||||
|
torch.sdaa.set_device(device_index)
|
||||||
|
|
||||||
|
def current_device(self):
|
||||||
|
return torch.sdaa.current_device()
|
||||||
|
|
||||||
|
def current_device_name(self):
|
||||||
|
return 'sdaa:{}'.format(torch.sdaa.current_device())
|
||||||
|
|
||||||
|
def device_count(self):
|
||||||
|
return torch.sdaa.device_count()
|
||||||
|
|
||||||
|
def synchronize(self, device_index=None):
|
||||||
|
return torch.sdaa.synchronize(device_index)
|
||||||
|
|
||||||
|
# RNG APIs
|
||||||
|
def random(self):
|
||||||
|
return torch.random
|
||||||
|
|
||||||
|
def set_rng_state(self, new_state, device_index=None):
|
||||||
|
if device_index is None:
|
||||||
|
return torch.sdaa.set_rng_state(new_state)
|
||||||
|
|
||||||
|
return torch.sdaa.set_rng_state(new_state, device_index)
|
||||||
|
|
||||||
|
def get_rng_state(self, device_index=None):
|
||||||
|
if device_index is None:
|
||||||
|
return torch.sdaa.get_rng_state()
|
||||||
|
|
||||||
|
return torch.sdaa.get_rng_state(device_index)
|
||||||
|
|
||||||
|
def manual_seed(self, seed):
|
||||||
|
return torch.sdaa.manual_seed(seed)
|
||||||
|
|
||||||
|
def manual_seed_all(self, seed):
|
||||||
|
return torch.sdaa.manual_seed_all(seed)
|
||||||
|
|
||||||
|
def initial_seed(self):
|
||||||
|
return torch.sdaa.initial_seed()
|
||||||
|
|
||||||
|
def default_generator(self, device_index):
|
||||||
|
return torch.sdaa.default_generators[device_index]
|
||||||
|
|
||||||
|
# Streams/Events
|
||||||
|
@property
|
||||||
|
def Stream(self):
|
||||||
|
return torch.sdaa.Stream
|
||||||
|
|
||||||
|
def stream(self, stream):
|
||||||
|
return torch.sdaa.stream(stream)
|
||||||
|
|
||||||
|
def current_stream(self, device_index=None):
|
||||||
|
return torch.sdaa.current_stream(device_index)
|
||||||
|
|
||||||
|
def default_stream(self, device_index=None):
|
||||||
|
return torch.sdaa.default_stream(device_index)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def Event(self):
|
||||||
|
return torch.sdaa.Event
|
||||||
|
|
||||||
|
# Memory management
|
||||||
|
def empty_cache(self):
|
||||||
|
return torch.sdaa.empty_cache()
|
||||||
|
|
||||||
|
def memory_allocated(self, device_index=None):
|
||||||
|
return torch.sdaa.memory_allocated(device_index)
|
||||||
|
|
||||||
|
def max_memory_allocated(self, device_index=None):
|
||||||
|
return torch.sdaa.max_memory_allocated(device_index)
|
||||||
|
|
||||||
|
def reset_max_memory_allocated(self, device_index=None):
|
||||||
|
return torch.sdaa.reset_max_memory_allocated(device_index)
|
||||||
|
|
||||||
|
def memory_cached(self, device_index=None):
|
||||||
|
return torch.sdaa.memory_cached(device_index)
|
||||||
|
|
||||||
|
def max_memory_cached(self, device_index=None):
|
||||||
|
return torch.sdaa.max_memory_cached(device_index)
|
||||||
|
|
||||||
|
def reset_max_memory_cached(self, device_index=None):
|
||||||
|
return torch.sdaa.reset_max_memory_cached(device_index)
|
||||||
|
|
||||||
|
def memory_stats(self, device_index=None):
|
||||||
|
if hasattr(torch.sdaa, 'memory_stats'):
|
||||||
|
return torch.sdaa.memory_stats(device_index)
|
||||||
|
|
||||||
|
def reset_peak_memory_stats(self, device_index=None):
|
||||||
|
if hasattr(torch.sdaa, 'reset_peak_memory_stats'):
|
||||||
|
return torch.sdaa.reset_peak_memory_stats(device_index)
|
||||||
|
|
||||||
|
def memory_reserved(self, device_index=None):
|
||||||
|
if hasattr(torch.sdaa, 'memory_reserved'):
|
||||||
|
return torch.sdaa.memory_reserved(device_index)
|
||||||
|
|
||||||
|
def max_memory_reserved(self, device_index=None):
|
||||||
|
if hasattr(torch.sdaa, 'max_memory_reserved'):
|
||||||
|
return torch.sdaa.max_memory_reserved(device_index)
|
||||||
|
|
||||||
|
def total_memory(self, device_index=None):
|
||||||
|
return torch.sdaa.get_device_properties(device_index).total_memory
|
||||||
|
|
||||||
|
def available_memory(self, device_index=None):
|
||||||
|
return self.total_memory(device_index) - self.memory_allocated(device_index)
|
||||||
|
|
||||||
|
# Data types
|
||||||
|
def is_bf16_supported(self):
|
||||||
|
return torch.sdaa.is_bf16_supported()
|
||||||
|
|
||||||
|
def is_fp16_supported(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def supported_dtypes(self):
|
||||||
|
supported_dtypes = [torch.float]
|
||||||
|
if self.is_fp16_supported():
|
||||||
|
supported_dtypes.append(torch.half)
|
||||||
|
if self.is_bf16_supported():
|
||||||
|
supported_dtypes.append(torch.bfloat16)
|
||||||
|
return supported_dtypes
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
def is_available(self):
|
||||||
|
return torch.sdaa.is_available()
|
||||||
|
|
||||||
|
def range_push(self, msg, domain=None, category=None):
|
||||||
|
return
|
||||||
|
|
||||||
|
def range_pop(self, domain=None):
|
||||||
|
return
|
||||||
|
|
||||||
|
def lazy_call(self, callback):
|
||||||
|
return torch.sdaa._lazy_call(callback)
|
||||||
|
|
||||||
|
def communication_backend_name(self):
|
||||||
|
return self._communication_backend_name
|
||||||
|
|
||||||
|
def is_triton_supported(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Graph operations
|
||||||
|
def create_graph(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def capture_to_graph(self, graph, pool=None, stream=None):
|
||||||
|
from deepspeed.runtime.utils import noop_context
|
||||||
|
return noop_context()
|
||||||
|
|
||||||
|
def replay_graph(self, graph):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Tensor operations
|
||||||
|
|
||||||
|
@property
|
||||||
|
def BFloat16Tensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.bfloat16, device='sdaa')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ByteTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.uint8, device='sdaa')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def DoubleTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.double, device='sdaa')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def FloatTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.float, device='sdaa')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def HalfTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.half, device='sdaa')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def IntTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.int, device='sdaa')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def LongTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.long, device='sdaa')
|
||||||
|
|
||||||
|
def pin_memory(self, tensor, align_bytes=1):
|
||||||
|
return tensor.pin_memory()
|
||||||
|
|
||||||
|
def is_pinned(self, tensor):
|
||||||
|
return tensor.is_pinned()
|
||||||
|
|
||||||
|
def on_accelerator(self, tensor):
|
||||||
|
device_str = str(tensor.device)
|
||||||
|
if device_str.startswith('sdaa:'):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def op_builder_dir(self):
|
||||||
|
try:
|
||||||
|
# is op_builder from deepspeed or a 3p version? this should only succeed if it's deepspeed
|
||||||
|
# if successful this also means we're doing a local install and not JIT compile path
|
||||||
|
from op_builder import __deepspeed__ # noqa: F401 # type: ignore
|
||||||
|
return "op_builder.sdaa"
|
||||||
|
except ImportError:
|
||||||
|
return "deepspeed.ops.op_builder.sdaa"
|
||||||
|
|
||||||
|
def _lazy_init_class_dict(self):
|
||||||
|
if self.class_dict:
|
||||||
|
return
|
||||||
|
|
||||||
|
op_builder_module = importlib.import_module(self.op_builder_dir())
|
||||||
|
|
||||||
|
# get op builder class from op_builder/sdaa/__init__.py
|
||||||
|
self.class_dict = {}
|
||||||
|
for class_name, class_obj in inspect.getmembers(op_builder_module, inspect.isclass):
|
||||||
|
self.class_dict[class_name] = class_obj
|
||||||
|
|
||||||
|
# create an instance of op builder and return, name specified by class_name
|
||||||
|
def create_op_builder(self, class_name):
|
||||||
|
builder_class = self.get_op_builder(class_name)
|
||||||
|
return builder_class()
|
||||||
|
|
||||||
|
# return an op builder class, name specified by class_name
|
||||||
|
def get_op_builder(self, class_name):
|
||||||
|
self._lazy_init_class_dict()
|
||||||
|
if class_name in self.class_dict:
|
||||||
|
return self.class_dict[class_name]
|
||||||
|
else:
|
||||||
|
return self.class_dict['NotImplementedBuilder']
|
||||||
|
|
||||||
|
def build_extension(self):
|
||||||
|
from torch.utils.cpp_extension import BuildExtension
|
||||||
|
return BuildExtension
|
||||||
|
|
||||||
|
def export_envs(self):
|
||||||
|
return ['NCCL', 'LD_LIBRARY', 'PATH']
|
||||||
|
|
||||||
|
def visible_devices_envs(self):
|
||||||
|
return ['SDAA_VISIBLE_DEVICES']
|
||||||
|
|
||||||
|
def set_visible_devices_envs(self, current_env, local_accelerator_ids):
|
||||||
|
for env in self.visible_devices_envs():
|
||||||
|
current_env[env] = ",".join(map(str, local_accelerator_ids))
|
||||||
|
|
||||||
|
def get_compile_backend(self):
|
||||||
|
return self._compile_backend
|
||||||
|
|
||||||
|
def set_compile_backend(self, backend):
|
||||||
|
supported_backends = torch._dynamo.list_backends(exclude_tags=())
|
||||||
|
if backend in supported_backends:
|
||||||
|
self._compile_backend = backend
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
f"{backend} not supported by {self.device_name()}. Supported Backends are {supported_backends}")
|
||||||
@@ -0,0 +1,293 @@
|
|||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
# DeepSpeed Team
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import pkgutil
|
||||||
|
import importlib
|
||||||
|
|
||||||
|
import torch
|
||||||
|
from .abstract_accelerator import DeepSpeedAccelerator
|
||||||
|
|
||||||
|
|
||||||
|
class SUPA_Accelerator(DeepSpeedAccelerator):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._name = 'supa'
|
||||||
|
# Use BCCL on Linux, fall back to gloo on Windows (no BCCL support yet)
|
||||||
|
self._communication_backend_name = 'bccl' if sys.platform != 'win32' else 'gloo'
|
||||||
|
self._compile_backend = "inductor"
|
||||||
|
|
||||||
|
def is_synchronized_device(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def use_host_timers(self):
|
||||||
|
return self.is_synchronized_device()
|
||||||
|
|
||||||
|
def resolves_data_dependency(self):
|
||||||
|
return self.is_synchronized_device()
|
||||||
|
|
||||||
|
def handles_memory_backpressure(self):
|
||||||
|
return self.is_synchronized_device()
|
||||||
|
|
||||||
|
# Device APIs
|
||||||
|
def device_name(self, device_index=None):
|
||||||
|
if device_index is None:
|
||||||
|
return 'supa'
|
||||||
|
return 'supa:{}'.format(device_index)
|
||||||
|
|
||||||
|
def communication_backend_version(self):
|
||||||
|
# BCCL does not expose a version via torch.supa
|
||||||
|
return (0, 0, 0)
|
||||||
|
|
||||||
|
def device(self, device_index=None):
|
||||||
|
return torch.device('supa', device_index)
|
||||||
|
|
||||||
|
def set_device(self, device_index):
|
||||||
|
torch.supa.set_device(device_index)
|
||||||
|
|
||||||
|
def current_device(self):
|
||||||
|
return torch.supa.current_device()
|
||||||
|
|
||||||
|
def current_device_name(self):
|
||||||
|
return 'supa:{}'.format(torch.supa.current_device())
|
||||||
|
|
||||||
|
def device_count(self):
|
||||||
|
return torch.supa.device_count()
|
||||||
|
|
||||||
|
def synchronize(self, device_index=None):
|
||||||
|
return torch.supa.synchronize(device_index)
|
||||||
|
|
||||||
|
# RNG APIs
|
||||||
|
def random(self):
|
||||||
|
return torch.random
|
||||||
|
|
||||||
|
def set_rng_state(self, new_state, device_index=None):
|
||||||
|
if device_index is None:
|
||||||
|
return torch.supa.set_rng_state(new_state)
|
||||||
|
return torch.supa.set_rng_state(new_state, device_index)
|
||||||
|
|
||||||
|
def get_rng_state(self, device_index=None):
|
||||||
|
if device_index is None:
|
||||||
|
return torch.supa.get_rng_state()
|
||||||
|
return torch.supa.get_rng_state(device_index)
|
||||||
|
|
||||||
|
def manual_seed(self, seed):
|
||||||
|
return torch.supa.manual_seed(seed)
|
||||||
|
|
||||||
|
def manual_seed_all(self, seed):
|
||||||
|
return torch.supa.manual_seed_all(seed)
|
||||||
|
|
||||||
|
def initial_seed(self):
|
||||||
|
return torch.supa.initial_seed()
|
||||||
|
|
||||||
|
def default_generator(self, device_index):
|
||||||
|
return torch.supa.default_generators[device_index]
|
||||||
|
|
||||||
|
# Streams/Events
|
||||||
|
@property
|
||||||
|
def Stream(self):
|
||||||
|
return torch.supa.Stream
|
||||||
|
|
||||||
|
def stream(self, stream):
|
||||||
|
return torch.supa.stream(stream)
|
||||||
|
|
||||||
|
def current_stream(self, device_index=None):
|
||||||
|
return torch.supa.current_stream(device_index)
|
||||||
|
|
||||||
|
def default_stream(self, device_index=None):
|
||||||
|
return torch.supa.default_stream(device_index)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def Event(self):
|
||||||
|
return torch.supa.Event
|
||||||
|
|
||||||
|
# Memory management
|
||||||
|
def empty_cache(self):
|
||||||
|
return torch.supa.empty_cache()
|
||||||
|
|
||||||
|
def memory_allocated(self, device_index=None):
|
||||||
|
return torch.supa.memory_allocated(device_index)
|
||||||
|
|
||||||
|
def max_memory_allocated(self, device_index=None):
|
||||||
|
return torch.supa.max_memory_allocated(device_index)
|
||||||
|
|
||||||
|
def reset_max_memory_allocated(self, device_index=None):
|
||||||
|
return torch.supa.reset_max_memory_allocated(device_index)
|
||||||
|
|
||||||
|
def memory_cached(self, device_index=None):
|
||||||
|
return torch.supa.memory_cached(device_index)
|
||||||
|
|
||||||
|
def max_memory_cached(self, device_index=None):
|
||||||
|
return torch.supa.max_memory_cached(device_index)
|
||||||
|
|
||||||
|
def reset_max_memory_cached(self, device_index=None):
|
||||||
|
return torch.supa.reset_max_memory_cached(device_index)
|
||||||
|
|
||||||
|
def memory_stats(self, device_index=None):
|
||||||
|
if hasattr(torch.supa, 'memory_stats'):
|
||||||
|
return torch.supa.memory_stats(device_index)
|
||||||
|
|
||||||
|
def reset_peak_memory_stats(self, device_index=None):
|
||||||
|
if hasattr(torch.supa, 'reset_peak_memory_stats'):
|
||||||
|
return torch.supa.reset_peak_memory_stats(device_index)
|
||||||
|
|
||||||
|
def memory_reserved(self, device_index=None):
|
||||||
|
if hasattr(torch.supa, 'memory_reserved'):
|
||||||
|
return torch.supa.memory_reserved(device_index)
|
||||||
|
|
||||||
|
def max_memory_reserved(self, device_index=None):
|
||||||
|
if hasattr(torch.supa, 'max_memory_reserved'):
|
||||||
|
return torch.supa.max_memory_reserved(device_index)
|
||||||
|
|
||||||
|
def total_memory(self, device_index=None):
|
||||||
|
return torch.supa.get_device_properties(device_index).total_memory
|
||||||
|
|
||||||
|
def available_memory(self, device_index=None):
|
||||||
|
return self.total_memory(device_index) - self.memory_allocated(device_index)
|
||||||
|
|
||||||
|
# Data types
|
||||||
|
def is_bf16_supported(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def is_fp16_supported(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def supported_dtypes(self):
|
||||||
|
return [torch.float, torch.half, torch.bfloat16]
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
def is_available(self):
|
||||||
|
return torch.supa.is_available()
|
||||||
|
|
||||||
|
def range_push(self, msg, domain=None, category=None):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def range_pop(self, domain=None):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def lazy_call(self, callback):
|
||||||
|
return torch.supa._lazy_call(callback)
|
||||||
|
|
||||||
|
def communication_backend_name(self):
|
||||||
|
return self._communication_backend_name
|
||||||
|
|
||||||
|
def is_triton_supported(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Graph operations
|
||||||
|
def create_graph(self):
|
||||||
|
return torch.supa.SUPAGraph()
|
||||||
|
|
||||||
|
def capture_to_graph(self, graph, pool=None, stream=None):
|
||||||
|
return torch.supa.graph(graph, pool, stream)
|
||||||
|
|
||||||
|
def replay_graph(self, graph):
|
||||||
|
graph.replay()
|
||||||
|
|
||||||
|
# Tensor operations
|
||||||
|
@property
|
||||||
|
def BFloat16Tensor(self):
|
||||||
|
return torch.supa.BFloat16Tensor
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ByteTensor(self):
|
||||||
|
return torch.supa.ByteTensor
|
||||||
|
|
||||||
|
@property
|
||||||
|
def DoubleTensor(self):
|
||||||
|
return torch.supa.DoubleTensor
|
||||||
|
|
||||||
|
@property
|
||||||
|
def FloatTensor(self):
|
||||||
|
return torch.supa.FloatTensor
|
||||||
|
|
||||||
|
@property
|
||||||
|
def HalfTensor(self):
|
||||||
|
return torch.supa.HalfTensor
|
||||||
|
|
||||||
|
@property
|
||||||
|
def IntTensor(self):
|
||||||
|
return torch.supa.IntTensor
|
||||||
|
|
||||||
|
@property
|
||||||
|
def LongTensor(self):
|
||||||
|
return torch.supa.LongTensor
|
||||||
|
|
||||||
|
def pin_memory(self, tensor, align_bytes=1):
|
||||||
|
return tensor.pin_memory()
|
||||||
|
|
||||||
|
def is_pinned(self, tensor):
|
||||||
|
return tensor.is_pinned()
|
||||||
|
|
||||||
|
def on_accelerator(self, tensor):
|
||||||
|
device_str = str(tensor.device)
|
||||||
|
return device_str.startswith('supa:')
|
||||||
|
|
||||||
|
def op_builder_dir(self):
|
||||||
|
try:
|
||||||
|
# Local install: op_builder is a top-level package
|
||||||
|
from op_builder import __deepspeed__ # noqa: F401 # type: ignore
|
||||||
|
return "op_builder.supa"
|
||||||
|
except ImportError:
|
||||||
|
return "deepspeed.ops.op_builder.supa"
|
||||||
|
|
||||||
|
# dict that holds class name <--> class type mapping i.e.
|
||||||
|
# 'FusedAdamBuilder': <class 'op_builder.supa.fused_adam.FusedAdamBuilder'>
|
||||||
|
# populated lazily on first call to create_op_builder / get_op_builder
|
||||||
|
class_dict = None
|
||||||
|
|
||||||
|
def _lazy_init_class_dict(self):
|
||||||
|
if self.class_dict is not None:
|
||||||
|
return
|
||||||
|
self.class_dict = {}
|
||||||
|
op_builder_dir = self.op_builder_dir()
|
||||||
|
op_builder_module = importlib.import_module(op_builder_dir)
|
||||||
|
op_builder_absolute_path = os.path.dirname(op_builder_module.__file__)
|
||||||
|
for _, module_name, _ in pkgutil.iter_modules([op_builder_absolute_path]):
|
||||||
|
if module_name in ('all_ops', 'builder') or os.path.isdir(
|
||||||
|
os.path.join(op_builder_absolute_path, module_name)):
|
||||||
|
continue
|
||||||
|
module = importlib.import_module("{}.{}".format(op_builder_dir, module_name))
|
||||||
|
for member_name in module.__dir__():
|
||||||
|
if (member_name.endswith('Builder')
|
||||||
|
and member_name not in ('OpBuilder', 'CUDAOpBuilder', 'TorchCPUOpBuilder', 'SUPAOpBuilder')):
|
||||||
|
if member_name not in self.class_dict:
|
||||||
|
self.class_dict[member_name] = getattr(module, member_name)
|
||||||
|
|
||||||
|
def create_op_builder(self, class_name):
|
||||||
|
self._lazy_init_class_dict()
|
||||||
|
if class_name in self.class_dict:
|
||||||
|
return self.class_dict[class_name]()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_op_builder(self, class_name):
|
||||||
|
self._lazy_init_class_dict()
|
||||||
|
if class_name in self.class_dict:
|
||||||
|
return self.class_dict[class_name]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def build_extension(self):
|
||||||
|
from torch.utils.cpp_extension import BuildExtension
|
||||||
|
return BuildExtension
|
||||||
|
|
||||||
|
def export_envs(self):
|
||||||
|
return ['BCCL', 'BIREN', 'SUPA', 'LD_LIBRARY', 'PATH']
|
||||||
|
|
||||||
|
def visible_devices_envs(self):
|
||||||
|
return ['SUPA_VISIBLE_DEVICES']
|
||||||
|
|
||||||
|
def set_visible_devices_envs(self, current_env, local_accelerator_ids):
|
||||||
|
for env in self.visible_devices_envs():
|
||||||
|
current_env[env] = ",".join(map(str, local_accelerator_ids))
|
||||||
|
|
||||||
|
def get_compile_backend(self):
|
||||||
|
return self._compile_backend
|
||||||
|
|
||||||
|
def set_compile_backend(self, backend):
|
||||||
|
supported_backends = torch._dynamo.list_backends(exclude_tags=())
|
||||||
|
if backend in supported_backends:
|
||||||
|
self._compile_backend = backend
|
||||||
|
else:
|
||||||
|
raise ValueError(f"{backend} not supported by {self.device_name()}. "
|
||||||
|
f"Supported backends: {supported_backends}")
|
||||||
@@ -0,0 +1,315 @@
|
|||||||
|
# Copyright (c) Microsoft Corporation.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
# DeepSpeed Team
|
||||||
|
|
||||||
|
import torch
|
||||||
|
from deepspeed.accelerator.abstract_accelerator import DeepSpeedAccelerator
|
||||||
|
import functools
|
||||||
|
import importlib
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
try:
|
||||||
|
import oneccl_bindings_for_pytorch # noqa: F401 # type: ignore
|
||||||
|
oneccl_imported_p = True
|
||||||
|
except ImportError as e:
|
||||||
|
oneccl_imported_p = False
|
||||||
|
|
||||||
|
|
||||||
|
class XPU_Accelerator(DeepSpeedAccelerator):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._name = 'xpu'
|
||||||
|
if oneccl_imported_p:
|
||||||
|
self._communication_backend_name = 'ccl'
|
||||||
|
else:
|
||||||
|
# changed to xccl if not using torch-CCL on XPU device
|
||||||
|
self._communication_backend_name = 'xccl'
|
||||||
|
self._compile_backend = "inductor"
|
||||||
|
self.aligned_tensors = []
|
||||||
|
self.class_dict = None
|
||||||
|
|
||||||
|
def is_synchronized_device(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def use_host_timers(self):
|
||||||
|
return self.is_synchronized_device()
|
||||||
|
|
||||||
|
def resolves_data_dependency(self):
|
||||||
|
return self.is_synchronized_device()
|
||||||
|
|
||||||
|
def handles_memory_backpressure(self):
|
||||||
|
return self.is_synchronized_device()
|
||||||
|
|
||||||
|
# Device APIs
|
||||||
|
def device_name(self, device_index=None):
|
||||||
|
if device_index == None:
|
||||||
|
return 'xpu'
|
||||||
|
return 'xpu:{}'.format(device_index)
|
||||||
|
|
||||||
|
def device(self, device_index=None):
|
||||||
|
return torch.device('xpu', device_index)
|
||||||
|
|
||||||
|
def set_device(self, device_index):
|
||||||
|
torch.xpu.set_device(device_index)
|
||||||
|
|
||||||
|
def current_device(self):
|
||||||
|
return torch.xpu.current_device()
|
||||||
|
|
||||||
|
def current_device_name(self):
|
||||||
|
return 'xpu:{}'.format(torch.xpu.current_device())
|
||||||
|
|
||||||
|
def device_count(self):
|
||||||
|
return torch.xpu.device_count()
|
||||||
|
|
||||||
|
def synchronize(self, device_index=None):
|
||||||
|
return torch.xpu.synchronize(device_index)
|
||||||
|
|
||||||
|
# RNG APIs
|
||||||
|
def random(self):
|
||||||
|
return torch.xpu.random
|
||||||
|
|
||||||
|
def set_rng_state(self, new_state, device_index=None):
|
||||||
|
if device_index == None:
|
||||||
|
return torch.xpu.set_rng_state(new_state)
|
||||||
|
return torch.xpu.set_rng_state(new_state, device_index)
|
||||||
|
|
||||||
|
def get_rng_state(self, device_index=None):
|
||||||
|
if device_index == None:
|
||||||
|
return torch.xpu.get_rng_state()
|
||||||
|
return torch.xpu.get_rng_state(device_index)
|
||||||
|
|
||||||
|
def manual_seed(self, seed):
|
||||||
|
return torch.xpu.manual_seed(seed)
|
||||||
|
|
||||||
|
def manual_seed_all(self, seed):
|
||||||
|
return torch.xpu.manual_seed_all(seed)
|
||||||
|
|
||||||
|
def initial_seed(self):
|
||||||
|
return torch.xpu.initial_seed()
|
||||||
|
|
||||||
|
def default_generator(self, device_index):
|
||||||
|
return torch.xpu.default_generators[device_index]
|
||||||
|
|
||||||
|
# Streams/Events
|
||||||
|
@property
|
||||||
|
def Stream(self):
|
||||||
|
return torch.xpu.Stream
|
||||||
|
|
||||||
|
def stream(self, stream):
|
||||||
|
return torch.xpu.stream(stream)
|
||||||
|
|
||||||
|
def current_stream(self, device_index=None):
|
||||||
|
return torch.xpu.current_stream(device_index)
|
||||||
|
|
||||||
|
def default_stream(self, device_index=None):
|
||||||
|
# torch.xpu does not support the sync behavior of default stream as cuda
|
||||||
|
# use current_stream as workaround
|
||||||
|
# see https://pytorch.org/docs/stable/notes/cuda.html#cuda-streams
|
||||||
|
return torch.xpu.current_stream(device_index)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def Event(self):
|
||||||
|
return torch.xpu.Event
|
||||||
|
|
||||||
|
# Memory management
|
||||||
|
def empty_cache(self):
|
||||||
|
return torch.xpu.empty_cache()
|
||||||
|
|
||||||
|
def memory_allocated(self, device_index=None):
|
||||||
|
return torch.xpu.memory_allocated(device_index)
|
||||||
|
|
||||||
|
def max_memory_allocated(self, device_index=None):
|
||||||
|
return torch.xpu.max_memory_allocated(device_index)
|
||||||
|
|
||||||
|
def reset_max_memory_allocated(self, device_index=None):
|
||||||
|
return torch.xpu.reset_max_memory_allocated(device_index)
|
||||||
|
|
||||||
|
def memory_cached(self, device_index=None):
|
||||||
|
return torch.xpu.memory_reserved(device_index)
|
||||||
|
|
||||||
|
def max_memory_cached(self, device_index=None):
|
||||||
|
return torch.xpu.max_memory_reserved(device_index)
|
||||||
|
|
||||||
|
def reset_max_memory_cached(self, device_index=None):
|
||||||
|
return torch.xpu.reset_max_memory_reserved(device_index)
|
||||||
|
|
||||||
|
def memory_stats(self, device_index=None):
|
||||||
|
return torch.xpu.memory_stats(device_index)
|
||||||
|
|
||||||
|
def reset_peak_memory_stats(self, device_index=None):
|
||||||
|
return torch.xpu.reset_peak_memory_stats(device_index)
|
||||||
|
|
||||||
|
def memory_reserved(self, device_index=None):
|
||||||
|
return torch.xpu.memory_reserved(device_index)
|
||||||
|
|
||||||
|
def max_memory_reserved(self, device_index=None):
|
||||||
|
return torch.xpu.max_memory_reserved(device_index)
|
||||||
|
|
||||||
|
def total_memory(self, device_index=None):
|
||||||
|
return torch.xpu.get_device_properties(device_index).total_memory
|
||||||
|
|
||||||
|
def available_memory(self, device_index=None):
|
||||||
|
return self.total_memory(device_index) - self.memory_allocated(device_index)
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
def is_available(self):
|
||||||
|
return torch.xpu.is_available()
|
||||||
|
|
||||||
|
def range_push(self, msg, domain=None, category=None):
|
||||||
|
# TODO itt is currently not supported yet
|
||||||
|
# return torch.profiler.itt.range_push(msg)
|
||||||
|
return
|
||||||
|
|
||||||
|
def range_pop(self, domain=None):
|
||||||
|
# TODO itt is currently not supported yet
|
||||||
|
# return torch.profiler.itt.range_pop()
|
||||||
|
return
|
||||||
|
|
||||||
|
def lazy_call(self, callback):
|
||||||
|
if hasattr(torch.xpu, "_lazy_call"):
|
||||||
|
return torch.xpu._lazy_call(callback)
|
||||||
|
else:
|
||||||
|
return torch.xpu.lazy_init._lazy_call(callback)
|
||||||
|
|
||||||
|
def communication_backend_name(self):
|
||||||
|
return self._communication_backend_name
|
||||||
|
|
||||||
|
def is_triton_supported(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Graph operations
|
||||||
|
def create_graph(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def capture_to_graph(self, graph, pool=None, stream=None):
|
||||||
|
from deepspeed.runtime.utils import noop_context
|
||||||
|
return noop_context()
|
||||||
|
|
||||||
|
def replay_graph(self, graph):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Data types
|
||||||
|
def is_bf16_supported(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def is_fp16_supported(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def supported_dtypes(self):
|
||||||
|
return [torch.float, torch.half, torch.bfloat16]
|
||||||
|
|
||||||
|
# Tensor operations
|
||||||
|
|
||||||
|
@property
|
||||||
|
def BFloat16Tensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.bfloat16, device=self._name)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ByteTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.uint8, device=self._name)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def DoubleTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.double, device=self._name)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def FloatTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.float, device=self._name)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def HalfTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.half, device=self._name)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def IntTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.int, device=self._name)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def LongTensor(self):
|
||||||
|
return functools.partial(torch.tensor, dtype=torch.long, device=self._name)
|
||||||
|
|
||||||
|
def pin_memory(self, tensor, align_bytes=1):
|
||||||
|
if align_bytes == 1:
|
||||||
|
return tensor.pin_memory(device=self.current_device_name())
|
||||||
|
elif align_bytes == 0:
|
||||||
|
from deepspeed.ops.op_builder.xpu import AsyncIOBuilder
|
||||||
|
self.aio_handle = AsyncIOBuilder().load().aio_handle(128 * 1024, 8, False, False, False)
|
||||||
|
aligned_t = self.aio_handle.new_cpu_locked_tensor(tensor.numel(), tensor)
|
||||||
|
aligned_t = aligned_t[:tensor.numel()].copy_(tensor)
|
||||||
|
self.aligned_tensors.append([aligned_t.data_ptr(), aligned_t[-1].data_ptr()])
|
||||||
|
return aligned_t
|
||||||
|
|
||||||
|
def is_pinned(self, tensor):
|
||||||
|
if tensor.is_pinned(device=self.current_device_name()):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
for begin, end in self.aligned_tensors:
|
||||||
|
if begin <= tensor.data_ptr() and tensor.data_ptr() <= end:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def op_builder_dir(self):
|
||||||
|
try:
|
||||||
|
# is op_builder from deepspeed or a 3p version? this should only succeed if it's deepspeed
|
||||||
|
# if successful this also means we're doing a local install and not JIT compile path
|
||||||
|
from op_builder import __deepspeed__ # noqa: F401 # type: ignore
|
||||||
|
return "op_builder.xpu"
|
||||||
|
except ImportError:
|
||||||
|
return "deepspeed.ops.op_builder.xpu"
|
||||||
|
|
||||||
|
def on_accelerator(self, tensor):
|
||||||
|
device_str = str(tensor.device)
|
||||||
|
if device_str.startswith('xpu:'):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _lazy_init_class_dict(self):
|
||||||
|
if self.class_dict:
|
||||||
|
return
|
||||||
|
|
||||||
|
op_builder_module = importlib.import_module(self.op_builder_dir())
|
||||||
|
|
||||||
|
# get op builder class from op_builder/xpu/__init__.py
|
||||||
|
self.class_dict = {}
|
||||||
|
for class_name, class_obj in inspect.getmembers(op_builder_module, inspect.isclass):
|
||||||
|
self.class_dict[class_name] = class_obj
|
||||||
|
|
||||||
|
# create an instance of op builder and return, name specified by class_name
|
||||||
|
def create_op_builder(self, class_name):
|
||||||
|
builder_class = self.get_op_builder(class_name)
|
||||||
|
return builder_class()
|
||||||
|
|
||||||
|
# return an op builder class, name specified by class_name
|
||||||
|
def get_op_builder(self, class_name):
|
||||||
|
self._lazy_init_class_dict()
|
||||||
|
if class_name in self.class_dict:
|
||||||
|
return self.class_dict[class_name]
|
||||||
|
else:
|
||||||
|
return self.class_dict['NotImplementedBuilder']
|
||||||
|
|
||||||
|
def build_extension(self):
|
||||||
|
from torch.utils.cpp_extension import BuildExtension
|
||||||
|
return BuildExtension
|
||||||
|
|
||||||
|
def export_envs(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def visible_devices_envs(self):
|
||||||
|
return ['ZE_AFFINITY_MASK']
|
||||||
|
|
||||||
|
def set_visible_devices_envs(self, current_env, local_accelerator_ids):
|
||||||
|
for env in self.visible_devices_envs():
|
||||||
|
current_env[env] = ",".join(map(str, local_accelerator_ids))
|
||||||
|
|
||||||
|
def get_compile_backend(self):
|
||||||
|
return self._compile_backend
|
||||||
|
|
||||||
|
def set_compile_backend(self, backend):
|
||||||
|
supported_backends = torch._dynamo.list_backends(exclude_tags=())
|
||||||
|
if backend in supported_backends:
|
||||||
|
self._compile_backend = backend
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
f"{backend} not supported by {self.device_name()}. Supported Backends are {supported_backends}")
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Getting Started with DeepSpeed on Azure
|
||||||
|
|
||||||
|
The recommended and simplest method to try DeepSpeed on Azure is through [AzureML](https://azure.microsoft.com/en-us/services/machine-learning/). For more details, please see our [Azure tutorial](https://www.deepspeed.ai/tutorials/azure/).
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# DeepSpeed Benchmarks
|
||||||
|
|
||||||
|
If you are looking for DeepSpeed benchmarks, please see the following resources:
|
||||||
|
|
||||||
|
1. [Communication Benchmarking Suite](https://github.com/deepspeedai/DeepSpeedExamples/tree/master/benchmarks/communication)
|
||||||
|
2. [Inference Benchmarks](https://github.com/deepspeedai/DeepSpeedExamples/tree/master/benchmarks/inference)
|
||||||
@@ -0,0 +1,275 @@
|
|||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
# DeepSpeed Team
|
||||||
|
"""
|
||||||
|
Benchmark: AutoSP multimodal sequence parallelism (ViT SP + fusion adapter).
|
||||||
|
|
||||||
|
Measures per-iteration latency, throughput, and peak GPU memory for the
|
||||||
|
ViT-SP + fusion-adapter pipeline at a given SP degree.
|
||||||
|
|
||||||
|
Launch (from repo root):
|
||||||
|
|
||||||
|
# SP degree 2 — two GPUs:
|
||||||
|
NCCL_P2P_DISABLE=1 torchrun --nproc_per_node=2 \\
|
||||||
|
benchmarks/autosp/bench_multimodal_sp.py [args]
|
||||||
|
|
||||||
|
# Baseline — single GPU (all-gather/scatter are no-ops):
|
||||||
|
torchrun --nproc_per_node=1 \\
|
||||||
|
benchmarks/autosp/bench_multimodal_sp.py [args]
|
||||||
|
|
||||||
|
Compare the two output tables to quantify memory savings and throughput scaling.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
--arch {internvl, qwen2vl} architecture to simulate (default: internvl)
|
||||||
|
--batch-size N samples per batch (default: 2)
|
||||||
|
--seq-len N text sequence length (default: 512)
|
||||||
|
--visual-tokens N total visual tokens per sample (default: 256)
|
||||||
|
--hidden N hidden dimension (default: 1024)
|
||||||
|
--num-layers N ViT and LLM layers each (default: 2)
|
||||||
|
--iters N measured iterations (default: 50)
|
||||||
|
--warmup N warmup iterations (default: 10)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
import statistics
|
||||||
|
|
||||||
|
import torch
|
||||||
|
import torch.nn as nn
|
||||||
|
|
||||||
|
import deepspeed
|
||||||
|
import deepspeed.comm as dist
|
||||||
|
from deepspeed.accelerator import get_accelerator
|
||||||
|
from deepspeed.sequence.auto_sp import auto_wrap_model_for_sp
|
||||||
|
from deepspeed.sequence.autosp_fusion import InternVLFusionAdapter, Qwen2VLFusionAdapter
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Token IDs
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_INTERNVL_CONTEXT_ID = 92546
|
||||||
|
_QWEN2VL_START_ID = 151652
|
||||||
|
_QWEN2VL_END_ID = 151653
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Mock attention classes — names match autosp_detector registries exactly
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
class InternVisionAttention(nn.Module):
|
||||||
|
|
||||||
|
def forward(self, hidden_states, **kwargs):
|
||||||
|
return hidden_states
|
||||||
|
|
||||||
|
|
||||||
|
class InternLM2Attention(nn.Module):
|
||||||
|
|
||||||
|
def forward(self, hidden_states, **kwargs):
|
||||||
|
return hidden_states
|
||||||
|
|
||||||
|
|
||||||
|
class Qwen2VLVisionAttention(nn.Module):
|
||||||
|
|
||||||
|
def forward(self, hidden_states, **kwargs):
|
||||||
|
return hidden_states
|
||||||
|
|
||||||
|
|
||||||
|
class Qwen2Attention(nn.Module):
|
||||||
|
|
||||||
|
def forward(self, hidden_states, **kwargs):
|
||||||
|
return hidden_states
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Model building blocks
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
class _ViTBlock(nn.Module):
|
||||||
|
"""One ViT transformer block: attention (to be SP-wrapped) + linear FFN."""
|
||||||
|
|
||||||
|
def __init__(self, attn_cls, hidden: int) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.attn = attn_cls()
|
||||||
|
self.ffn = nn.Linear(hidden, hidden, bias=False)
|
||||||
|
|
||||||
|
def forward(self, x, **kwargs):
|
||||||
|
out = self.attn(x, **kwargs)
|
||||||
|
if isinstance(out, (tuple, list)):
|
||||||
|
out = out[0]
|
||||||
|
return self.ffn(out)
|
||||||
|
|
||||||
|
|
||||||
|
class _MinimalInternVLModel(nn.Module):
|
||||||
|
"""InternVL-like benchmark model.
|
||||||
|
|
||||||
|
Module paths detected by autosp_detector:
|
||||||
|
- ``vision_encoder.*.attn`` -> InternVisionAttention (_VIT_ATTN_CLASSNAMES)
|
||||||
|
- ``mm_projector`` -> keyword in _VISION_PROJ_KEYWORDS
|
||||||
|
|
||||||
|
``language_model`` uses plain nn.Linear layers so it is NOT wrapped by
|
||||||
|
DistributedAttention (avoids the Q/K/V interface requirement) yet still
|
||||||
|
contributes realistic compute on the scattered fused sequence.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, hidden: int, num_layers: int) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.vision_encoder = nn.Sequential(*[_ViTBlock(InternVisionAttention, hidden) for _ in range(num_layers)])
|
||||||
|
self.mm_projector = nn.Identity()
|
||||||
|
self.language_model = nn.Sequential(*[nn.Linear(hidden, hidden, bias=False) for _ in range(num_layers)])
|
||||||
|
self.fusion = None
|
||||||
|
|
||||||
|
def forward(self, local_patches: torch.Tensor, text_embeds: torch.Tensor, input_ids: torch.Tensor) -> torch.Tensor:
|
||||||
|
local_visual = self.vision_encoder(local_patches)
|
||||||
|
local_fused = self.fusion(local_visual, text_embeds, input_ids)
|
||||||
|
return self.language_model(local_fused)
|
||||||
|
|
||||||
|
|
||||||
|
class _MinimalQwen2VLModel(nn.Module):
|
||||||
|
"""Qwen2VL-like benchmark model."""
|
||||||
|
|
||||||
|
def __init__(self, hidden: int, num_layers: int) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.visual = nn.Sequential(*[_ViTBlock(Qwen2VLVisionAttention, hidden) for _ in range(num_layers)])
|
||||||
|
self.multi_modal_projector = nn.Identity()
|
||||||
|
self.model = nn.Sequential(*[nn.Linear(hidden, hidden, bias=False) for _ in range(num_layers)])
|
||||||
|
self.fusion = None
|
||||||
|
|
||||||
|
def forward(self, local_patches: torch.Tensor, text_embeds: torch.Tensor, input_ids: torch.Tensor) -> torch.Tensor:
|
||||||
|
local_visual = self.visual(local_patches)
|
||||||
|
local_fused = self.fusion(local_visual, text_embeds, input_ids)
|
||||||
|
return self.model(local_fused)
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Setup helpers
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
def _build_model_and_inputs(arch: str, args, sp_group, device):
|
||||||
|
rank = dist.get_rank(sp_group)
|
||||||
|
world_size = dist.get_world_size(sp_group)
|
||||||
|
|
||||||
|
local_v = args.visual_tokens // world_size
|
||||||
|
bs, text_len, hidden = args.batch_size, args.seq_len, args.hidden
|
||||||
|
|
||||||
|
torch.manual_seed(0)
|
||||||
|
local_patches = torch.randn(bs, local_v, hidden, device=device)
|
||||||
|
text_embeds = torch.randn(bs, text_len, hidden, device=device)
|
||||||
|
input_ids = torch.zeros(bs, text_len, dtype=torch.long, device=device)
|
||||||
|
|
||||||
|
if arch == "internvl":
|
||||||
|
num_ctx = min(local_v * world_size, text_len - 2)
|
||||||
|
input_ids[:, 2:2 + num_ctx] = _INTERNVL_CONTEXT_ID
|
||||||
|
|
||||||
|
model = _MinimalInternVLModel(hidden, args.num_layers).to(device)
|
||||||
|
# Suppress the Phase 2 projection-layer warning: we wrap manually below.
|
||||||
|
_auto_sp_logger = logging.getLogger("deepspeed.sequence.auto_sp")
|
||||||
|
_prev_level = _auto_sp_logger.level
|
||||||
|
_auto_sp_logger.setLevel(logging.ERROR)
|
||||||
|
auto_wrap_model_for_sp(model, sp_group)
|
||||||
|
_auto_sp_logger.setLevel(_prev_level)
|
||||||
|
model.fusion = InternVLFusionAdapter(model.mm_projector, sp_group,
|
||||||
|
image_token_id=_INTERNVL_CONTEXT_ID).to(device)
|
||||||
|
else: # qwen2vl
|
||||||
|
num_inner = min(local_v * world_size, text_len - 3)
|
||||||
|
input_ids[:, 1] = _QWEN2VL_START_ID
|
||||||
|
input_ids[:, 2 + num_inner] = _QWEN2VL_END_ID
|
||||||
|
|
||||||
|
model = _MinimalQwen2VLModel(hidden, args.num_layers).to(device)
|
||||||
|
_auto_sp_logger = logging.getLogger("deepspeed.sequence.auto_sp")
|
||||||
|
_prev_level = _auto_sp_logger.level
|
||||||
|
_auto_sp_logger.setLevel(logging.ERROR)
|
||||||
|
auto_wrap_model_for_sp(model, sp_group)
|
||||||
|
_auto_sp_logger.setLevel(_prev_level)
|
||||||
|
model.fusion = Qwen2VLFusionAdapter(model.multi_modal_projector,
|
||||||
|
sp_group,
|
||||||
|
vision_start_token_id=_QWEN2VL_START_ID,
|
||||||
|
vision_end_token_id=_QWEN2VL_END_ID).to(device)
|
||||||
|
|
||||||
|
return model, local_patches, text_embeds, input_ids
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Benchmark runner
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
def _run(arch: str, args) -> None:
|
||||||
|
deepspeed.init_distributed(dist_backend="nccl")
|
||||||
|
rank = dist.get_rank()
|
||||||
|
world_size = dist.get_world_size()
|
||||||
|
device = torch.device(get_accelerator().device_name(), rank % get_accelerator().device_count())
|
||||||
|
get_accelerator().set_device(rank % get_accelerator().device_count())
|
||||||
|
|
||||||
|
sp_group = dist.new_group(ranks=list(range(world_size)))
|
||||||
|
model, local_patches, text_embeds, input_ids = _build_model_and_inputs(arch, args, sp_group, device)
|
||||||
|
model.eval()
|
||||||
|
|
||||||
|
# Warmup
|
||||||
|
with torch.no_grad():
|
||||||
|
for _ in range(args.warmup):
|
||||||
|
model(local_patches, text_embeds, input_ids)
|
||||||
|
get_accelerator().synchronize()
|
||||||
|
get_accelerator().reset_peak_memory_stats()
|
||||||
|
|
||||||
|
# Timed iterations using CUDA events for accurate GPU-side measurement.
|
||||||
|
latencies_ms = []
|
||||||
|
with torch.no_grad():
|
||||||
|
for _ in range(args.iters):
|
||||||
|
t_start = get_accelerator().Event(enable_timing=True)
|
||||||
|
t_end = get_accelerator().Event(enable_timing=True)
|
||||||
|
t_start.record()
|
||||||
|
model(local_patches, text_embeds, input_ids)
|
||||||
|
t_end.record()
|
||||||
|
get_accelerator().synchronize()
|
||||||
|
latencies_ms.append(t_start.elapsed_time(t_end))
|
||||||
|
|
||||||
|
peak_mem_mb = get_accelerator().max_memory_allocated() / 1024**2
|
||||||
|
mean_ms = statistics.mean(latencies_ms)
|
||||||
|
std_ms = statistics.stdev(latencies_ms) if len(latencies_ms) > 1 else 0.0
|
||||||
|
# tokens/s: fused sequence length approximated by seq_len (length-preserving adapters).
|
||||||
|
throughput = (args.batch_size * args.seq_len) / (mean_ms / 1000.0)
|
||||||
|
|
||||||
|
if rank == 0:
|
||||||
|
sep = "=" * 62
|
||||||
|
print(f"\n{sep}")
|
||||||
|
print(f" AutoSP Benchmark arch={arch} sp_degree={world_size}")
|
||||||
|
print(sep)
|
||||||
|
print(f" batch_size : {args.batch_size}")
|
||||||
|
print(f" seq_len : {args.seq_len}")
|
||||||
|
print(f" visual_tokens : {args.visual_tokens} (local={args.visual_tokens // world_size}/rank)")
|
||||||
|
print(f" hidden : {args.hidden}")
|
||||||
|
print(f" num_layers : {args.num_layers}")
|
||||||
|
print(f" warmup / iters : {args.warmup} / {args.iters}")
|
||||||
|
print(f" {'─' * 58}")
|
||||||
|
print(f" Latency : {mean_ms:.2f} ± {std_ms:.2f} ms/iter")
|
||||||
|
print(f" Throughput : {throughput:,.0f} tokens/s")
|
||||||
|
print(f" Peak GPU memory : {peak_mem_mb:.1f} MB")
|
||||||
|
print(f"{sep}\n")
|
||||||
|
|
||||||
|
dist.destroy_process_group()
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
parser = argparse.ArgumentParser(description="AutoSP multimodal SP benchmark")
|
||||||
|
parser.add_argument("--arch",
|
||||||
|
choices=["internvl", "qwen2vl"],
|
||||||
|
default="internvl",
|
||||||
|
help="Model architecture to simulate")
|
||||||
|
parser.add_argument("--batch-size", type=int, default=2)
|
||||||
|
parser.add_argument("--seq-len", type=int, default=512)
|
||||||
|
parser.add_argument("--visual-tokens",
|
||||||
|
type=int,
|
||||||
|
default=256,
|
||||||
|
help="Total visual tokens (must be divisible by --nproc_per_node)")
|
||||||
|
parser.add_argument("--hidden", type=int, default=1024)
|
||||||
|
parser.add_argument("--num-layers", type=int, default=2, help="Number of ViT blocks and LLM linear layers each")
|
||||||
|
parser.add_argument("--iters", type=int, default=50)
|
||||||
|
parser.add_argument("--warmup", type=int, default=10)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
_run(args.arch, args)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
ds
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
@echo off
|
||||||
|
python "%~dp0\ds" %*
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
ds
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from deepspeed.launcher.runner import main
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from benchmarks.communication.run_all import main
|
||||||
|
from benchmarks.communication.constants import *
|
||||||
|
from benchmarks.communication.utils import *
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Run the same file with deepspeed launcher. This is required since setuptools will auto-detect python files and insert a python shebang for both 'scripts' and 'entry_points', and this benchmarks require the DS launcher
|
||||||
|
required_env = ["RANK", "WORLD_SIZE", "MASTER_ADDR", "MASTER_PORT", "LOCAL_RANK"]
|
||||||
|
if not all(map(lambda v: v in os.environ, required_env)):
|
||||||
|
import subprocess
|
||||||
|
r = subprocess.check_output(["which", "ds_bench"])
|
||||||
|
ds_bench_bin = r.decode('utf-8').strip()
|
||||||
|
safe_cmd = ["deepspeed", ds_bench_bin] + sys.argv[1:]
|
||||||
|
subprocess.run(safe_cmd)
|
||||||
|
else:
|
||||||
|
args = benchmark_parser().parse_args()
|
||||||
|
rank = args.local_rank
|
||||||
|
main(args, rank)
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
|
||||||
|
import deepspeed
|
||||||
|
from deepspeed.elasticity import compute_elastic_config
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('-c', '--config', type=str, help="DeepSpeed config json")
|
||||||
|
parser.add_argument('-w', '--world-size', type=int, default=0, help="Intended/current world size")
|
||||||
|
args = parser.parse_args()
|
||||||
|
ds_config = json.load(open(args.config, 'r'))
|
||||||
|
|
||||||
|
ds_version = deepspeed.__version__
|
||||||
|
|
||||||
|
elastic_config = ds_config['elasticity']
|
||||||
|
print('------------------------------------------')
|
||||||
|
print("Elasticity config:")
|
||||||
|
print('------------------------------------------')
|
||||||
|
print(json.dumps(elastic_config, indent=4, sort_keys=True))
|
||||||
|
|
||||||
|
if args.world_size > 0:
|
||||||
|
final_batch_size, valid_gpus, micro_batch_size = compute_elastic_config(ds_config=ds_config,
|
||||||
|
target_deepspeed_version=ds_version,
|
||||||
|
world_size=args.world_size)
|
||||||
|
print('------------------------------------------')
|
||||||
|
print(f"Calculated results for world size {args.world_size}:")
|
||||||
|
print('------------------------------------------')
|
||||||
|
print(f'final_batch_size .... {final_batch_size}')
|
||||||
|
print(f'valid_gpus .......... {valid_gpus}')
|
||||||
|
print(f'micro_batch_size .... {micro_batch_size}')
|
||||||
|
else:
|
||||||
|
final_batch_size, valid_gpus = compute_elastic_config(ds_config=ds_config, target_deepspeed_version=ds_version)
|
||||||
|
print('------------------------------------------')
|
||||||
|
print("Calculated results:")
|
||||||
|
print('------------------------------------------')
|
||||||
|
print(f'final_batch_size .... {final_batch_size}')
|
||||||
|
print(f'valid_gpus .......... {valid_gpus}')
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from deepspeed.nvme import ds_io_main
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
ds_io_main()
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from deepspeed.nvme import sweep_main, generate_main, parse_sweep_arguments
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
args = parse_sweep_arguments()
|
||||||
|
print(f"Running DeepNVMe performance tuning on {args.nvme_dir}")
|
||||||
|
sweep_main(args)
|
||||||
|
generate_main(args.log_dir)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from deepspeed.env_report import cli_main
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
cli_main()
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
@echo off
|
||||||
|
python "%~dp0\ds_report" %*
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Copyright 2020 The Microsoft DeepSpeed Team
|
||||||
|
|
||||||
|
command -v pdsh
|
||||||
|
if [ $? != 0 ]; then
|
||||||
|
echo "Cannot find pdsh, please install via 'apt-get install -y pdsh'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
hostfile=/job/hostfile
|
||||||
|
|
||||||
|
while getopts "h?f:" opt; do
|
||||||
|
case "$opt" in
|
||||||
|
h|\?)
|
||||||
|
echo "-f <hostfile>: specify a hostfile, defaults to /job/hostfile"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
f)
|
||||||
|
hostfile=$OPTARG
|
||||||
|
shift $((OPTIND-1))
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "hostfile=$hostfile"
|
||||||
|
|
||||||
|
if [ -f $hostfile ]; then
|
||||||
|
hosts=`cat $hostfile | awk '{print $1}' | paste -sd "," -`
|
||||||
|
export PDSH_RCMD_TYPE=ssh
|
||||||
|
pdsh -w ${hosts} $@
|
||||||
|
else
|
||||||
|
echo "Missing hostfile at ${hostfile}, unable to proceed"
|
||||||
|
fi
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
All DeepSpeed blogs are linked here:
|
||||||
|
After Width: | Height: | Size: 612 KiB |
|
After Width: | Height: | Size: 167 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 120 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 844 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 82 KiB |