├── .coveragerc ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── documentation.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml ├── mergify.yml ├── stale.yml └── workflows │ ├── ci-tests.yml │ ├── ci_install-pkg.yml │ ├── ci_schema.yml │ ├── code-format.yml │ ├── docs-check.yml │ ├── docs-deploy.yml │ ├── greetings.yml │ └── release-pypi.yml ├── .gitignore ├── .lightningignore ├── .pre-commit-config.yaml ├── LICENSE ├── MANIFEST.in ├── README.md ├── app.py ├── docs ├── .build_docs.sh ├── Makefile ├── make.bat └── source │ ├── _static │ ├── copybutton.js │ └── images │ │ ├── icon.svg │ │ ├── logo-large.svg │ │ ├── logo-small.svg │ │ └── logo.png │ ├── _templates │ └── theme_variables.jinja │ ├── app.py │ ├── conf.py │ ├── example │ ├── artifacts.bash │ ├── data.bash │ ├── experiment.bash │ ├── experiment_args.bash │ ├── help.bash │ ├── logs.bash │ ├── prepare.bash │ ├── script.py │ ├── show_experiment_and_sweep.bash │ ├── stop_delete.bash │ ├── sweep.bash │ ├── sweep_args.bash │ └── sweep_hydra.bash │ ├── get_started │ ├── fundamentals.rst │ ├── lightning_hpo.rst │ └── what_app_can_do.rst │ ├── index.rst │ ├── install_beginner.rst │ ├── installation.rst │ ├── installation_mac.rst │ ├── installation_win.rst │ ├── more_examples │ ├── llms.rst │ └── llms │ │ ├── clone.bash │ │ ├── experiment.bash │ │ └── scale.bash │ ├── setup │ ├── connect.bash │ ├── duplicate.bash │ └── pip.bash │ ├── training_studio.rst │ └── workflows │ ├── connect_or_disconnect.rst │ ├── convert_from_raw_optuna.rst │ ├── loggers.rst │ ├── loggers │ ├── streamlit.rst │ ├── tensorboard.rst │ └── wandb.rst │ ├── optimize_an_objective.rst │ ├── optimize_an_objective_context.rst │ ├── optimize_with_pytorch_lightning.rst │ ├── run_notebook.rst │ ├── run_sweep.rst │ ├── run_training_studio_app.rst │ ├── scripts │ └── optuna_pruning.py │ ├── show_notebooks.rst │ ├── show_or_download_artifacts.rst │ ├── show_or_download_logs.rst │ ├── show_sweeps.rst │ ├── stop_or_delete_notebook.rst │ ├── stop_or_delete_sweep.rst │ └── sweep.rst ├── lightning_training_studio ├── __about__.py ├── __init__.py ├── algorithm │ ├── __init__.py │ ├── base.py │ └── optuna.py ├── app │ ├── __init__.py │ ├── main.py │ └── ui │ │ ├── .prettierrc │ │ ├── README.md │ │ ├── build │ │ ├── asset-manifest.json │ │ ├── favicon.svg │ │ ├── index.html │ │ ├── manifest.json │ │ ├── robots.txt │ │ └── static │ │ │ ├── css │ │ │ ├── main.bbbac2be.css │ │ │ └── main.bbbac2be.css.map │ │ │ ├── js │ │ │ ├── 787.9615c779.chunk.js │ │ │ ├── 787.9615c779.chunk.js.map │ │ │ ├── main.7b96e885.js │ │ │ ├── main.7b96e885.js.LICENSE.txt │ │ │ └── main.7b96e885.js.map │ │ │ └── media │ │ │ ├── UCity-Light.30446c15a21bf8a994e8.woff2 │ │ │ ├── UCity-Light.47cf3e33cb6bb1496c95.woff │ │ │ ├── UCity-Regular.7a3b475525ed92dc7816.woff │ │ │ ├── UCity-Regular.8afa44ac39706d62b62b.woff2 │ │ │ ├── UCity-Semibold.80655a0e8b4bb5f30545.woff2 │ │ │ ├── UCity-Semibold.bb7aab96e378ebd6a651.woff │ │ │ ├── cloud.7aee0ddfc3bf81079995a22e719e53fb.svg │ │ │ ├── error.11892047d0183a4723b91dc0fb98cb95.svg │ │ │ ├── success.5edae4c5b171e2c1c5a3c54273c47ba8.svg │ │ │ └── warning.5c542673e84e77ceb6a230bfea7f7263.svg │ │ ├── craco.config.js │ │ ├── package.json │ │ ├── public │ │ ├── favicon.svg │ │ ├── index.html │ │ ├── manifest.json │ │ └── robots.txt │ │ ├── spec.json │ │ ├── src │ │ ├── App.tsx │ │ ├── assets │ │ │ └── cloud.svg │ │ ├── components │ │ │ ├── BorderLinearProgress.tsx │ │ │ ├── DataTable.tsx │ │ │ ├── ExperimentTable.tsx │ │ │ ├── LightningToggleButtonGroup.tsx │ │ │ ├── MoreMenu.tsx │ │ │ ├── StartStopMenuItem.tsx │ │ │ ├── Tabs.tsx │ │ │ └── UserGuide.tsx │ │ ├── generated │ │ │ ├── AppClient.ts │ │ │ ├── core │ │ │ │ ├── ApiError.ts │ │ │ │ ├── ApiRequestOptions.ts │ │ │ │ ├── ApiResult.ts │ │ │ │ ├── AxiosHttpRequest.ts │ │ │ │ ├── BaseHttpRequest.ts │ │ │ │ ├── CancelablePromise.ts │ │ │ │ ├── OpenAPI.ts │ │ │ │ └── request.ts │ │ │ ├── index.ts │ │ │ ├── models │ │ │ │ ├── Body_upload_file_api_v1_upload_file__filename__put.ts │ │ │ │ ├── DataConfig.ts │ │ │ │ ├── DeleteDataConfig.ts │ │ │ │ ├── DeleteExperimentConfig.ts │ │ │ │ ├── DeleteSweepConfig.ts │ │ │ │ ├── Distributions.ts │ │ │ │ ├── DownloadArtifactsConfig.ts │ │ │ │ ├── ExperimentConfig.ts │ │ │ │ ├── HTTPValidationError.ts │ │ │ │ ├── ShowArtifactsConfig.ts │ │ │ │ ├── StopExperimentConfig.ts │ │ │ │ ├── StopSweepConfig.ts │ │ │ │ ├── StopTensorboardConfig.ts │ │ │ │ ├── SweepConfig.ts │ │ │ │ ├── TensorboardConfig.ts │ │ │ │ └── ValidationError.ts │ │ │ └── services │ │ │ │ ├── AppApiService.ts │ │ │ │ ├── AppClientCommandService.ts │ │ │ │ └── DefaultService.ts │ │ ├── hooks │ │ │ ├── useClientDataState.tsx │ │ │ ├── useSelectedTabState.tsx │ │ │ └── useShowHelpPageState.tsx │ │ ├── index.css │ │ ├── index.tsx │ │ ├── reportWebVitals.ts │ │ ├── svg.d.ts │ │ ├── types │ │ │ └── lightning.ts │ │ └── utilities.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ └── yarn.lock ├── commands │ ├── __init__.py │ ├── artifacts │ │ ├── __init__.py │ │ ├── download.py │ │ └── show.py │ ├── data │ │ ├── __init__.py │ │ ├── create.py │ │ ├── delete.py │ │ └── show.py │ ├── experiment │ │ ├── __init__.py │ │ ├── delete.py │ │ ├── run.py │ │ ├── show.py │ │ └── stop.py │ ├── logs │ │ └── show.py │ ├── notebook │ │ ├── __init__.py │ │ ├── run.py │ │ ├── show.py │ │ └── stop.py │ ├── sweep │ │ ├── __init__.py │ │ ├── delete.py │ │ ├── run.py │ │ ├── show.py │ │ └── stop.py │ └── tensorboard │ │ ├── __init__.py │ │ └── stop.py ├── components │ ├── __init__.py │ ├── notebook.py │ ├── sweep.py │ └── tensorboard.py ├── controllers │ ├── __init__.py │ ├── controller.py │ ├── notebook.py │ ├── sweep.py │ └── tensorboard.py ├── distributions │ ├── __init__.py │ └── distributions.py ├── framework │ ├── __init__.py │ ├── agnostic.py │ └── pytorch_lightning.py ├── loggers │ ├── __init__.py │ ├── logger.py │ ├── streamlit │ │ ├── __init__.py │ │ ├── hyperplot.py │ │ └── streamlit.py │ ├── tensorboard.py │ └── wandb.py ├── setup_tools.py └── utilities │ ├── __init__.py │ ├── enum.py │ ├── imports.py │ └── utils.py ├── requirements.txt ├── requirements ├── collect_env_details.py ├── docs.txt └── test.txt ├── setup.py ├── sweep_examples ├── 1_app_agnostic.py ├── 2_app_pytorch_lightning.py ├── 3_app_sklearn.py ├── 4_app_grid_search.py ├── 5_app_random_search.py ├── README.md ├── requirements.txt └── scripts │ ├── .lightningignore │ ├── big_model.py │ ├── data.py │ ├── objective.py │ ├── requirements.txt │ ├── train.py │ └── train_cifar.py └── tests ├── __init__.py ├── app └── test_main.py ├── commands ├── __init__.py ├── artifacts │ ├── __init__.py │ ├── test_download.py │ └── test_show.py ├── data │ └── test_create.py ├── experiment │ ├── __init__.py │ ├── test_requirements │ ├── test_run.py │ └── test_stop.py └── sweep │ ├── __init__.py │ ├── sweep_1.json │ ├── test_delete.py │ ├── test_run.py │ ├── test_show.py │ └── test_stop.py ├── components ├── __init__.py ├── test_sweep.py └── test_tensorboard.py ├── conftest.py ├── controllers ├── __init__.py ├── test_notebook.py ├── test_sweep.py └── test_tensorboard.py ├── features ├── environment.py ├── notebook.feature ├── steps │ ├── __init__.py │ ├── app.py │ ├── notebook.py │ └── sweep.py └── sweep.feature ├── helpers.py ├── loggers ├── __init__.py ├── test_streamlit.py ├── test_tensorboard.py └── test_wandb.py ├── test_examples.py └── utilities └── test_utils.py /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | source = 3 | lightning_training_studio 4 | concurrency = 5 | multiprocessing 6 | thread 7 | parallel = True 8 | omit = 9 | lightning_training_studio/setup_tools.py 10 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Each line is a file pattern followed by one or more owners. 2 | 3 | # These owners will be the default owners for everything in the repo. Unless a later match takes precedence, 4 | # @global-owner1 and @global-owner2 will be requested for review when someone opens a pull request. 5 | * @tchaton 6 | 7 | # Packages 8 | /lightning_training_studio @tchaton 9 | 10 | 11 | # Examples 12 | /examples @tchaton 13 | 14 | 15 | # Examples 16 | /examples @tchaton 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug, help wanted 6 | assignees: '' 7 | --- 8 | 9 | ## 🐛 Bug 10 | 11 | 12 | 13 | ### To Reproduce 14 | 15 | Steps to reproduce the behavior: 16 | 17 | 1. Go to '...' 18 | 1. Run '....' 19 | 1. Scroll down to '....' 20 | 1. See error 21 | 22 | 23 | 24 | #### Code sample 25 | 26 | 28 | 29 | ### Expected behavior 30 | 31 | 32 | 33 | ### Environment 34 | 35 | - PyTorch Version (e.g., 1.0): 36 | - OS (e.g., Linux): 37 | - How you installed PyTorch (`conda`, `pip`, source): 38 | - Build command you used (if compiling from source): 39 | - Python version: 40 | - CUDA/cuDNN version: 41 | - GPU models and configuration: 42 | - Any other relevant information: 43 | 44 | ### Additional context 45 | 46 | 47 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Typos and doc fixes 3 | about: Typos and doc fixes 4 | title: '' 5 | labels: documentation 6 | assignees: '' 7 | --- 8 | 9 | ## 📚 Documentation 10 | 11 | For typos and doc fixes, please go ahead and: 12 | 13 | 1. Create an issue. 14 | 1. Fix the typo. 15 | 1. Submit a PR. 16 | 17 | Thanks! 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement, help wanted 6 | assignees: '' 7 | --- 8 | 9 | ## 🚀 Feature 10 | 11 | 12 | 13 | ### Motivation 14 | 15 | 16 | 17 | ### Pitch 18 | 19 | 20 | 21 | ### Alternatives 22 | 23 | 24 | 25 | ### Additional context 26 | 27 | 28 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Before submitting 2 | 3 | - [ ] Was this discussed/approved via a Github issue? (no need for typos and docs improvements) 4 | - [ ] Did you read the [contributor guideline](https://github.com/Lightning-AI/lightning-hpo/blob/main/.github/CONTRIBUTING.md), Pull Request section? 5 | - [ ] Did you make sure to update the docs? 6 | - [ ] Did you write any new necessary tests? 7 | 8 | ## What does this PR do? 9 | 10 | Fixes # (issue). 11 | 12 | ## PR review 13 | 14 | Anyone in the community is free to review the PR once the tests have passed. 15 | If we didn't discuss your PR in Github issues there's a high chance it will not be merged. 16 | 17 | ## Did you have fun? 18 | 19 | Make sure you had fun coding 🙃 20 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Basic dependabot.yml file with 2 | # minimum configuration for two package managers 3 | 4 | version: 2 5 | updates: 6 | # Enable version updates for GitHub Actions 7 | - package-ecosystem: "github-actions" 8 | directory: "/" 9 | # Check for updates once a week 10 | schedule: 11 | interval: "weekly" 12 | # Labels on pull requests for version updates only 13 | labels: 14 | - "ci / tests" 15 | pull-request-branch-name: 16 | # Separate sections of the branch name with a hyphen 17 | # for example, `dependabot-npm_and_yarn-next_js-acorn-6.4.1` 18 | separator: "-" 19 | # Allow up to 5 open pull requests for GitHub Actions 20 | open-pull-requests-limit: 5 21 | reviewers: 22 | - "Lightning-AI/teams/core-lightning" 23 | -------------------------------------------------------------------------------- /.github/mergify.yml: -------------------------------------------------------------------------------- 1 | pull_request_rules: 2 | - name: warn on conflicts 3 | conditions: 4 | - conflict 5 | - -draft # filter-out GH draft PRs 6 | - -label="has conflicts" 7 | actions: 8 | # comment: 9 | # message: This pull request is now in conflict... :( 10 | label: 11 | add: ["has conflicts"] 12 | 13 | - name: resolved conflicts 14 | conditions: 15 | - -conflict 16 | - label="has conflicts" 17 | - -draft # filter-out GH draft PRs 18 | - -merged # not merged yet 19 | - -closed 20 | actions: 21 | label: 22 | remove: ["has conflicts"] 23 | 24 | - name: add core reviewer 25 | conditions: 26 | # number of review approvals 27 | - "#approved-reviews-by<2" 28 | actions: 29 | request_reviews: 30 | users: 31 | - Lightning-Universe/engs 32 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/marketplace/stale 2 | 3 | # Number of days of inactivity before an issue becomes stale 4 | daysUntilStale: 60 5 | # Number of days of inactivity before a stale issue is closed 6 | daysUntilClose: 14 7 | # Issues with these labels will never be considered stale 8 | exemptLabels: 9 | - pinned 10 | - security 11 | # Label to use when marking an issue as stale 12 | staleLabel: won't fix 13 | # Comment to post when marking an issue as stale. Set to `false` to disable 14 | markComment: > 15 | This issue has been automatically marked as stale because it has not had 16 | recent activity. It will be closed if no further activity occurs. Thank you 17 | for your contributions. 18 | # Comment to post when closing a stale issue. Set to `false` to disable 19 | closeComment: false 20 | 21 | # Set to true to ignore issues in a project (defaults to false) 22 | exemptProjects: true 23 | # Set to true to ignore issues in a milestone (defaults to false) 24 | exemptMilestones: true 25 | # Set to true to ignore issues with an assignee (defaults to false) 26 | exemptAssignees: true 27 | -------------------------------------------------------------------------------- /.github/workflows/ci_install-pkg.yml: -------------------------------------------------------------------------------- 1 | name: Install pkg 2 | 3 | # see: https://help.github.com/en/actions/reference/events-that-trigger-workflows 4 | on: # Trigger the workflow on push or pull request, but only for the master branch 5 | push: 6 | branches: 7 | - "master" 8 | pull_request: 9 | 10 | jobs: 11 | pkg-check: 12 | runs-on: ubuntu-20.04 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | - uses: actions/setup-python@v4 17 | with: 18 | python-version: 3.8 19 | 20 | - name: Check package 21 | run: | 22 | pip install check-manifest 23 | check-manifest 24 | python setup.py check --metadata --strict 25 | 26 | - name: Create package 27 | run: | 28 | pip install --upgrade setuptools wheel 29 | python setup.py sdist bdist_wheel 30 | 31 | - name: Verify package 32 | run: | 33 | pip install twine>=3.2 34 | twine check dist/* 35 | python setup.py clean 36 | 37 | pkg-install: 38 | runs-on: ${{ matrix.os }} 39 | strategy: 40 | fail-fast: false 41 | matrix: 42 | os: [ubuntu-20.04, macOS-11, windows-2022] 43 | python-version: [3.8] 44 | 45 | steps: 46 | - uses: actions/checkout@v3 47 | - uses: actions/setup-python@v4 48 | with: 49 | python-version: ${{ matrix.python-version }} 50 | 51 | - name: Create package 52 | run: | 53 | pip install --upgrade setuptools wheel 54 | python setup.py sdist bdist_wheel 55 | ls -l dist/ 56 | 57 | - name: Install package 58 | run: | 59 | pip install $(python -c "import glob ; print(glob.glob('dist/*.whl')[0])") 60 | cd .. 61 | python -c "import lightning ; print(lightning.__version__)" 62 | -------------------------------------------------------------------------------- /.github/workflows/ci_schema.yml: -------------------------------------------------------------------------------- 1 | name: CI action schema 2 | on: # Trigger the workflow on push or pull request, but only for the main branch 3 | push: {} 4 | pull_request: 5 | branches: [main, "release/*"] 6 | 7 | jobs: 8 | validate-schema: 9 | runs-on: ubuntu-20.04 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v3 13 | 14 | - name: Install pkg 15 | run: | 16 | pip install check-jsonschema 17 | pip list | grep jsonschema 18 | 19 | - name: GH Workflows 20 | run: check-jsonschema .github/workflows/*.yml --builtin-schema "github-workflows" 21 | -------------------------------------------------------------------------------- /.github/workflows/code-format.yml: -------------------------------------------------------------------------------- 1 | name: Check Code formatting 2 | 3 | # see: https://help.github.com/en/actions/reference/events-that-trigger-workflows 4 | on: # Trigger the workflow on push or pull request, but only for the main branch 5 | push: {} 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | # typing-check-mypy: 11 | # runs-on: ubuntu-20.04 12 | # steps: 13 | # - uses: actions/checkout@v3 14 | # - uses: actions/setup-python@v4 15 | # with: 16 | # python-version: 3.8 17 | # - name: Install mypy 18 | # run: | 19 | # pip install mypy 20 | # pip list 21 | # - name: mypy 22 | # run: | 23 | # mypy . 24 | 25 | pre-commit-check: 26 | runs-on: ubuntu-latest 27 | steps: 28 | - uses: actions/checkout@v3 29 | with: 30 | fetch-depth: 0 31 | - uses: actions/setup-python@v4 32 | 33 | - name: set PY 34 | run: echo "PY=$(python -VV | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV 35 | 36 | - uses: actions/cache@v3 37 | with: 38 | path: ~/.cache/pre-commit 39 | key: pre-commit|${{ env.PY }}|${{ hashFiles('.pre-commit-config.yaml') }} 40 | 41 | - uses: pre-commit/action@v3.0.0 42 | # this action also provides an additional behaviour when used in private repositories 43 | # when configured with a github token, the action will push back fixes to the pull request branch 44 | with: 45 | token: ${{ secrets.GITHUB_TOKEN }} 46 | -------------------------------------------------------------------------------- /.github/workflows/docs-deploy.yml: -------------------------------------------------------------------------------- 1 | name: "Deploy Docs" 2 | on: 3 | push: 4 | branches: [master] 5 | 6 | jobs: 7 | # https://github.com/marketplace/actions/deploy-to-github-pages 8 | build-docs-deploy: 9 | runs-on: ubuntu-20.04 10 | steps: 11 | - name: Checkout 🛎️ 12 | uses: actions/checkout@v3 13 | # If you're using actions/checkout@v3 you must set persist-credentials to false in most cases for the deployment to work correctly. 14 | with: 15 | persist-credentials: false 16 | - uses: actions/setup-python@v4 17 | with: 18 | python-version: 3.8 19 | 20 | # Note: This uses an internal pip API and may not always work 21 | # https://github.com/actions/cache/blob/master/examples.md#multiple-oss-in-a-workflow 22 | - name: Cache pip 23 | uses: actions/cache@v3 24 | with: 25 | path: ~/.cache/pip 26 | key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }} 27 | restore-keys: | 28 | ${{ runner.os }}-pip- 29 | 30 | - uses: aws-actions/configure-aws-credentials@v2 31 | with: 32 | aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} 33 | aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY_ID }} 34 | aws-region: us-east-1 35 | - run: aws s3 sync s3://sphinx-packages/ pypi/ 36 | 37 | - name: Install dependencies 38 | run: | 39 | pip install --requirement requirements.txt -U -f https://download.pytorch.org/whl/cpu/torch_stable.html --quiet 40 | pip install --requirement requirements/docs.txt -f pypi 41 | pip install -e . 42 | # install Texlive, see https://linuxconfig.org/how-to-install-latex-on-ubuntu-20-04-focal-fossa-linux 43 | sudo apt-get update 44 | sudo apt-get install -y texlive-latex-extra dvipng texlive-pictures 45 | python --version 46 | pip --version 47 | pip list 48 | shell: bash 49 | 50 | - name: Make Documentation 51 | working-directory: ./docs 52 | run: | 53 | # First run the same pipeline as Read-The-Docs 54 | make clean 55 | make html --jobs 2 56 | #touch build/html/.nojekyll 57 | 58 | - name: Deploy 🚀 59 | uses: JamesIves/github-pages-deploy-action@v4.4.1 60 | with: 61 | token: ${{ secrets.GITHUB_TOKEN }} 62 | branch: gh-pages # The branch the action should deploy to. 63 | folder: docs/build/html # The folder the action should deploy. 64 | clean: true # Automatically remove deleted files from the deploy branch 65 | target-folder: docs # If you'd like to push the contents of the deployment folder into a specific directory 66 | single-commit: true # you'd prefer to have a single commit on the deployment branch instead of full history 67 | if: success() 68 | -------------------------------------------------------------------------------- /.github/workflows/greetings.yml: -------------------------------------------------------------------------------- 1 | name: Greetings 2 | # https://github.com/marketplace/actions/first-interaction 3 | 4 | on: [issues] # pull_request 5 | 6 | jobs: 7 | greeting: 8 | runs-on: ubuntu-20.04 9 | steps: 10 | - uses: actions/first-interaction@v1 11 | with: 12 | repo-token: ${{ secrets.GITHUB_TOKEN }} 13 | issue-message: "Hi! thanks for your contribution!, great first issue!" 14 | pr-message: "Hey thanks for the input! Please give us a bit of time to review it!" 15 | -------------------------------------------------------------------------------- /.github/workflows/release-pypi.yml: -------------------------------------------------------------------------------- 1 | name: PyPI Release 2 | 3 | # https://help.github.com/en/actions/reference/events-that-trigger-workflows 4 | on: # Trigger the workflow on push to master branch with changes in __about__.py 5 | push: 6 | branches: 7 | - "master" 8 | paths: 9 | - "lightning_training_studio/__about__.py" 10 | 11 | # based on https://github.com/pypa/gh-action-pypi-publish 12 | jobs: 13 | build: 14 | runs-on: ubuntu-20.04 15 | 16 | steps: 17 | - uses: actions/checkout@v3 18 | - uses: actions/setup-python@v4 19 | with: 20 | python-version: 3.8 21 | 22 | - name: Install dependencies 23 | run: >- 24 | python -m pip install --user --upgrade setuptools wheel 25 | 26 | - name: Install Lightning 27 | run: | 28 | python -m pip install -r requirements.txt --quiet 29 | python -m pip install . --quiet 30 | 31 | - name: Build 32 | run: >- 33 | python setup.py sdist bdist_wheel 34 | 35 | - name: Publish distribution 📦 to PyPI 36 | uses: pypa/gh-action-pypi-publish@v1.8.5 37 | with: 38 | user: __token__ 39 | password: ${{ secrets.pypi_password }} 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | develop-eggs/ 12 | dist/ 13 | downloads/ 14 | eggs/ 15 | .eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | wheels/ 22 | pip-wheel-metadata/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .nox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *.cover 48 | *.py,cover 49 | .hypothesis/ 50 | .pytest_cache/ 51 | 52 | # Translations 53 | *.mo 54 | *.pot 55 | 56 | # Sphinx documentation 57 | docs/_build/ 58 | docs/source/api/ 59 | docs/source/*.md 60 | 61 | # PyBuilder 62 | target/ 63 | 64 | # Jupyter Notebook 65 | .ipynb_checkpoints 66 | 67 | # IPython 68 | profile_default/ 69 | ipython_config.py 70 | 71 | # pyenv 72 | .python-version 73 | 74 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 75 | __pypackages__/ 76 | 77 | # Celery stuff 78 | celerybeat-schedule 79 | celerybeat.pid 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | .dmypy.json 106 | dmypy.json 107 | 108 | # Pyre type checker 109 | .pyre/ 110 | 111 | # PyCharm 112 | .idea/ 113 | 114 | # Lightning logs 115 | lightning_logs 116 | *.gz 117 | .DS_Store 118 | .*_submit.py 119 | .vscode 120 | 121 | MNIST 122 | *.pt 123 | .storage/ 124 | .shared/ 125 | infra 126 | coverage.* 127 | # Frontend build artifacts 128 | 129 | *lightning_logs* 130 | .storage 131 | /data 132 | *.pt 133 | __py 134 | wandb 135 | config.yaml 136 | wandb 137 | *.ckpt 138 | *lightning-quick-start-quick_start_train* 139 | flagged 140 | file_server 141 | sweep-* 142 | train.py 143 | net.py 144 | thomas-* 145 | boring_train.py 146 | database.db 147 | artifacts/* 148 | tensorboard_logs 149 | jupyter_lab_* 150 | 151 | node_modules/ 152 | docs/build 153 | docs/_build 154 | cifar-10-batches-py 155 | -------------------------------------------------------------------------------- /.lightningignore: -------------------------------------------------------------------------------- 1 | *lightning_logs* 2 | .shared 3 | *.ckpt 4 | *.shared* 5 | *.git* 6 | *MNIST* 7 | *egg-info/* 8 | *model_weight.pt* 9 | *cifar-10-batches-py* 10 | flagged 11 | wandb 12 | .venv 13 | thomas-* 14 | venv 15 | dist 16 | tensorboard_logs 17 | jupyter_lab_* 18 | *node_modules* 19 | docs 20 | .storage 21 | .coverage 22 | coverage.xml 23 | LICENSE 24 | spec.json 25 | database.db 26 | examples 27 | data/* 28 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | default_language_version: 2 | python: python3 3 | 4 | ci: 5 | autofix_prs: true 6 | autoupdate_commit_msg: "[pre-commit.ci] pre-commit suggestions" 7 | autoupdate_schedule: "quarterly" 8 | 9 | repos: 10 | - repo: https://github.com/pre-commit/pre-commit-hooks 11 | rev: v4.4.0 12 | hooks: 13 | - id: end-of-file-fixer 14 | - id: trailing-whitespace 15 | - id: check-case-conflict 16 | - id: check-yaml 17 | - id: check-toml 18 | - id: check-json 19 | - id: check-added-large-files 20 | exclude: lightning_training_studio/app/ui/yarn.lock 21 | - id: check-docstring-first 22 | - id: detect-private-key 23 | 24 | - repo: https://github.com/asottile/pyupgrade 25 | rev: v3.3.1 26 | hooks: 27 | - id: pyupgrade 28 | args: [--py38-plus] 29 | name: Upgrade code 30 | 31 | - repo: https://github.com/PyCQA/docformatter 32 | rev: v1.5.1 33 | hooks: 34 | - id: docformatter 35 | args: [--in-place, --wrap-summaries=120, --wrap-descriptions=120] 36 | 37 | - repo: https://github.com/psf/black 38 | rev: 23.3.0 39 | hooks: 40 | - id: black 41 | name: Black code 42 | args: ["--line-length=120"] 43 | 44 | - repo: https://github.com/executablebooks/mdformat 45 | rev: 0.7.16 46 | hooks: 47 | - id: mdformat 48 | additional_dependencies: 49 | - mdformat-gfm 50 | - mdformat-black 51 | - mdformat_frontmatter 52 | 53 | - repo: https://github.com/charliermarsh/ruff-pre-commit 54 | rev: v0.0.260 55 | hooks: 56 | - id: ruff 57 | args: ["--fix", "--line-length=120"] 58 | 59 | - repo: https://github.com/pre-commit/mirrors-prettier 60 | rev: v2.7.1 61 | hooks: 62 | - id: prettier 63 | exclude: | 64 | (?x)( 65 | ^lightning_training_studio/app/ui/build| 66 | ^lightning_training_studio/app/ui/src/generated| 67 | README.md| 68 | ^.github| 69 | ^tests| 70 | ^docs 71 | ) 72 | additional_dependencies: 73 | - prettier@2.7.1 74 | - typescript@4.4.2 75 | - prettier-plugin-organize-imports@3.1.0 76 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.py 2 | include *.txt 3 | exclude *.yaml 4 | exclude *.toml 5 | exclude *.coveragerc 6 | exclude *.lightning 7 | exclude *.lightningignore 8 | exclude *.json 9 | exclude tests/commands/experiment/test_requirements 10 | 11 | recursive-include sweep_examples * 12 | recursive-include lightning_training_studio * 13 | recursive-include requirements * 14 | 15 | recursive-exclude docs * 16 | recursive-exclude tests *.py 17 | recursive-exclude tests *.feature 18 | recursive-exclude * *.pyc 19 | recursive-exclude * *.json 20 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | import os 2 | from textwrap import dedent 3 | 4 | import lightning as L 5 | from lightning.app.utilities import frontend 6 | 7 | from lightning_training_studio.app.main import TrainingStudio 8 | 9 | description = ( 10 | "The Lightning PyTorch Training Studio App is an AI application that uses the Lightning framework" 11 | " to run experiments or sweep with state-of-the-art algorithms, locally or in the cloud." 12 | ) 13 | 14 | on_connect_end = dedent( 15 | """ 16 | Run these commands to run your first Sweep: 17 | 18 | # Create a new folder 19 | mkdir new_folder && cd new_folder 20 | 21 | # Download example script 22 | curl -o train.py https://raw.githubusercontent.com/Lightning-AI/lightning-hpo/master/sweep_examples/scripts/train.py 23 | 24 | # Run a sweep 25 | lightning run sweep train.py --model.lr "[0.001, 0.01]" --data.batch "[32, 64]" --algorithm="grid_search" 26 | """ 27 | ) 28 | 29 | # TODO: Use redis queue for now. Http Queue aren't scaling as well. 30 | os.environ["LIGHTNING_CLOUD_QUEUE_TYPE"] = "redis" 31 | 32 | app = L.LightningApp( 33 | TrainingStudio(), 34 | info=frontend.AppInfo( 35 | title="Lightning PyTorch Training Studio", 36 | description=description, 37 | on_connect_end=on_connect_end, 38 | ), 39 | flow_cloud_compute=L.CloudCompute("cpu-small"), 40 | ) 41 | -------------------------------------------------------------------------------- /docs/.build_docs.sh: -------------------------------------------------------------------------------- 1 | make clean 2 | make html --debug --jobs $(nproc) 3 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = -W 6 | SPHINXBUILD = python $(shell which sphinx-build) 7 | SOURCEDIR = source 8 | BUILDDIR = build 9 | 10 | # Put it first so that "make" without argument is like "make help". 11 | help: 12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 13 | 14 | .PHONY: help Makefile 15 | 16 | # Catch-all target: route all unknown targets to Sphinx using the new 17 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 18 | %: Makefile 19 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 20 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/source/_static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/docs/source/_static/images/logo.png -------------------------------------------------------------------------------- /docs/source/_templates/theme_variables.jinja: -------------------------------------------------------------------------------- 1 | {%- set external_urls = { 2 | 'github': 'https://github.com/Lightning-AI/lightning-hpo', 3 | 'github_issues': 'https://github.com/Lightning-AI/lightning-hpo/issues', 4 | 'contributing': 'https://github.com/Lightning-AI/lightning/blob/master/CONTRIBUTING.md', 5 | 'governance': 'https://github.com/Lightning-AI/lightning/blob/master/governance.md', 6 | 'docs': 'https://lightning-ai.github.io/lightning-hpo', 7 | 'twitter': 'https://twitter.com/PyTorchLightnin', 8 | 'discuss': 'https://pytorch-lightning.slack.com', 9 | 'tutorials': 'https://pt-lightning-hpo.readthedocs.io/en/latest/#tutorials', 10 | 'previous_pytorch_versions': 'https://pt-lightning-hpo.rtfd.io/en/latest/', 11 | 'home': 'https://lightning-ai.github.io/lightning-hpo', 12 | 'get_started': 'https://lightning-ai.github.io/lightning-hpo/training_studio.html', 13 | 'features': 'https://pt-lightning-hpo.rtfd.io/en/latest/', 14 | 'blog': 'https://lightning.ai/pages/blog', 15 | 'resources': 'https://pt-lightning-hpo.readthedocs.io/en/latest/#community-examples', 16 | 'support': 'https://pt-lightning-hpo.rtfd.io/en/latest/', 17 | } 18 | -%} 19 | -------------------------------------------------------------------------------- /docs/source/app.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/docs/source/app.py -------------------------------------------------------------------------------- /docs/source/example/artifacts.bash: -------------------------------------------------------------------------------- 1 | # Create a tree with your artifacts 2 | lightning show artifacts 3 | 4 | # Create a tree with your artifacts for a Sweep 5 | lightning show artifacts --names grid_search 6 | 7 | # Create a tree with your artifacts for several Experiments 8 | lightning show artifacts --names my_first_training my_second_training 9 | 10 | # Download artifacts from Sweep 11 | lightning download artifacts --names grid_search --output_dir ./grid_search 12 | 13 | # Download artifacts from several experiments 14 | lightning download artifacts --names my_first_training my_second_training --output_dir ./experiments 15 | -------------------------------------------------------------------------------- /docs/source/example/data.bash: -------------------------------------------------------------------------------- 1 | # Add data from an S3 bucket 2 | # lightning add dataset --name {THE DATASET NAME} --source {WHERE THE DATA LIVES ON S3} 3 | lightning add dataset --name mnist --source s3://lightning-example-public/MNIST/ 4 | 5 | # Create a table with your Datasets 6 | lightning show datasets 7 | 8 | # Use your data with an Experiment. Format `:` 9 | lightning run experiment train.py --name experiment_with_data --data mnist:/content/data/MNIST/ 10 | -------------------------------------------------------------------------------- /docs/source/example/experiment.bash: -------------------------------------------------------------------------------- 1 | # Submit an experiment 2 | lightning run experiment train.py --name my_first_training 3 | 4 | # Submit another experiment on GPU 5 | lightning run experiment train.py --name my_second_training --cloud_compute="gpu" 6 | -------------------------------------------------------------------------------- /docs/source/example/experiment_args.bash: -------------------------------------------------------------------------------- 1 | # Submit an experiment 2 | 3 | # Specifying requirements in a requirements.txt file 4 | lightning run experiment --requirements=requirements.txt \ 5 | train.py --model.lr=0.001 --data.batch=32 6 | 7 | # Specifying a list of requirements 8 | # Specifying requirements in a file 9 | lightning run experiment --requirements="imgaug==0.4.0","pandas>=1.5.0" \ 10 | train.py --model.lr=0.001 --data.batch=32 11 | 12 | # Specifying system packages 13 | lightning run experiment --packages=ffmpeg,libsm6,libxext6 \ 14 | train.py --model.lr=0.001 --data.batch=32 15 | 16 | # Running pip install . on the source dir before running 17 | lightning run experiment --pip-install-source \ 18 | train.py --model.lr=0.001 --data.batch=32 19 | 20 | # Specifying cloud compute for each experiment in the sweep 21 | lightning run experiment --cloud-compute=gpu-fast \ 22 | train.py --model.lr=0.001 --data.batch=32 23 | 24 | # Hydra overrides work out of the box 25 | lightning run experiment --cloud-compute=gpu-fast \ 26 | train.py model.lr=0.001 data.batch=32 \ 27 | +trainer.accumulate_grad_batches=10 28 | -------------------------------------------------------------------------------- /docs/source/example/help.bash: -------------------------------------------------------------------------------- 1 | # Get information about the Sweep command 2 | lightning run sweep --help 3 | 4 | # Get more granular information for each command 5 | lightning run sweep --help 6 | 7 | lightning show logs --help 8 | 9 | # Any of the CLI commands. 10 | -------------------------------------------------------------------------------- /docs/source/example/logs.bash: -------------------------------------------------------------------------------- 1 | # View all the logs 2 | lightning show logs 3 | 4 | # View the logs for a single sweep 5 | lightning show logs --names bayesian_search 6 | 7 | # View the logs for a single experiment 8 | lightning show logs --names my_first_training 9 | 10 | # View the logs for a several experiments 11 | lightning show logs --names my_first_training my_second_training 12 | -------------------------------------------------------------------------------- /docs/source/example/prepare.bash: -------------------------------------------------------------------------------- 1 | # 1. Create a new folder 2 | mkdir new_folder && cd new_folder 3 | 4 | # 2. Copy & paste the example into a train.py file 5 | curl -o train.py https://raw.githubusercontent.com/Lightning-AI/lightning-hpo/master/sweep_examples/scripts/train.py 6 | -------------------------------------------------------------------------------- /docs/source/example/show_experiment_and_sweep.bash: -------------------------------------------------------------------------------- 1 | # Create a table of your Experiments 2 | lightning show experiments 3 | 4 | # Create a table of your Sweeps 5 | lightning show sweeps 6 | -------------------------------------------------------------------------------- /docs/source/example/stop_delete.bash: -------------------------------------------------------------------------------- 1 | # Stop an experiment 2 | lightning stop experiment --name my_first_training 3 | 4 | # Stop a sweep 5 | lightning stop sweep --name bayesian_search 6 | 7 | # Delete an experiment 8 | lightning delete experiment --name my_first_training 9 | 10 | # Delete a sweep 11 | lightning delete sweep --name bayesian_search 12 | -------------------------------------------------------------------------------- /docs/source/example/sweep.bash: -------------------------------------------------------------------------------- 1 | # Launch Sweeps over train.py file 2 | 3 | # Using Grid Search Algorithm 4 | lightning run sweep train.py \ 5 | --name grid_search \ 6 | --model.lr="[0.001, 0.1]" \ 7 | --data.batch="[32, 64]" \ 8 | --algorithm="grid_search" 9 | 10 | # Using Random Search Algorithm 11 | lightning run sweep train.py \ 12 | --name random_search \ 13 | --total_experiments=3 \ 14 | --model.lr="log_uniform(0.001, 0.1)" \ 15 | --data.batch='categorical([32, 64])' \ 16 | --algorithm="random_search" 17 | 18 | # Using Bayesian Search Algorithm with parallel experiments 19 | lightning run sweep train.py \ 20 | --name bayesian_search \ 21 | --total_experiments=5 \ 22 | --parallel_experiments=2 \ 23 | --model.lr="log_uniform(0.001, 0.1)" \ 24 | --data.batch='categorical([32, 64])' \ 25 | --algorithm="bayesian" 26 | -------------------------------------------------------------------------------- /docs/source/example/sweep_args.bash: -------------------------------------------------------------------------------- 1 | # Launch Sweeps over train.py file 2 | 3 | # Specifying requirements in a requirements.txt file 4 | lightning run sweep --requirements=requirements.txt \ 5 | train.py \ 6 | model.lr=0.001,0.1 \ 7 | data.batch=32,64 8 | 9 | # Specifying a list of requirements 10 | # Specifying requirements in a file 11 | lightning run sweep --requirements="imgaug==0.4.0","pandas>=1.5.0" \ 12 | train.py \ 13 | model.lr=0.001,0.1 \ 14 | data.batch=32,64 15 | 16 | # Specifying system packages 17 | lightning run sweep --packages=ffmpeg,libsm6,libxext6 \ 18 | train.py \ 19 | model.lr=0.001,0.1 \ 20 | data.batch=32,64 21 | 22 | # Running pip install . on the source dir before running 23 | lightning run sweep --pip-install-source \ 24 | train.py \ 25 | model.lr=0.001,0.1 \ 26 | data.batch=32,64 27 | 28 | # Specifying cloud compute for each experiment in the sweep 29 | lightning run sweep --cloud-compute=gpu-fast \ 30 | train.py \ 31 | model.lr=0.001,0.1 \ 32 | data.batch=32,64 33 | -------------------------------------------------------------------------------- /docs/source/example/sweep_hydra.bash: -------------------------------------------------------------------------------- 1 | # Launch Sweeps over train.py file using Hydra syntax 2 | # For an example on how to use Lightning + Hydra see 3 | # https://github.com/ashleve/lightning-hydra-template 4 | 5 | # All Hydra override syntax is supported, use the 6 | # syntax for Hydra multirun to define sweeps 7 | # https://hydra.cc/docs/tutorials/basic/running_your_app/multi-run/ 8 | lightning run sweep --syntax hydra train.py \ 9 | model.lr=0.001,0.1 \ 10 | data.batch=32,64 \ 11 | +trainer.accumulate_grad_batches=10 12 | -------------------------------------------------------------------------------- /docs/source/get_started/fundamentals.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | #################################################### 4 | Fundamentals about HyperParameter Optimization (HPO) 5 | #################################################### 6 | 7 | .. _fundamental: 8 | 9 | HyperParameter Optimization (HPO) can be applied to many things. 10 | 11 | .. join_slack:: 12 | :align: left 13 | 14 | ---- 15 | 16 | TODO 17 | -------------------------------------------------------------------------------- /docs/source/get_started/lightning_hpo.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | ####################################### 4 | Use Lightning HPO with your own scripts 5 | ####################################### 6 | 7 | .. _fundamental: 8 | 9 | Lightning HPO 10 | 11 | .. join_slack:: 12 | :align: left 13 | 14 | ---- 15 | 16 | TODO 17 | -------------------------------------------------------------------------------- /docs/source/installation.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | .. _install: 4 | 5 | 6 | ############ 7 | Installation 8 | ############ 9 | 10 | We strongly recommend to create a virtual environment first. 11 | Don't know what this is? Follow our `beginner guide here `_. 12 | 13 | **Requirements** 14 | 15 | * Python 3.8.x or later (3.8.x, 3.9.x, 3.10.x) 16 | 17 | Or read the `Apple Silicon Macs installation article `_ or the `Windows installation article `_. 18 | 19 | ---- 20 | 21 | **************** 22 | Install with pip 23 | **************** 24 | 25 | 0. Activate your virtual environment. 26 | 27 | You can use `conda `_ or `pyenv `_. 28 | 29 | 1. Install the ``lightning-hpo`` package 30 | 31 | .. code:: bash 32 | 33 | git clone https://github.com/Lightning-AI/lightning-hpo && cd lightning-hpo 34 | 35 | pip install -e . -r requirements.txt --find-links https://download.pytorch.org/whl/cpu/torch_stable.html 36 | 37 | .. note:: This is only temporary as some changes are being released to PiPy 38 | 39 | 40 | 2. Makes sure everything works locally 41 | 42 | .. code-block:: bash 43 | 44 | python -m lightning run app app.py 45 | 46 | 3. Makes sure everything works in the cloud 47 | 48 | .. code-block:: bash 49 | 50 | PACKAGE_LIGHTNING=1 python -m lightning run app app.py --cloud 51 | 52 | ---- 53 | 54 | ********** 55 | Next Steps 56 | ********** 57 | 58 | .. raw:: html 59 | 60 |
61 |
62 |
63 | 64 | .. displayitem:: 65 | :header: Run a Sweep with PyTorch Lightning 66 | :description: Discover PyTorch Lightning and train your first Model. 67 | :col_css: col-md-6 68 | :button_link: workflows/optimize_with_pytorch_lightning.html 69 | :height: 180 70 | 71 | .. displayitem:: 72 | :header: The Training Studio App 73 | :description: Manage Sweeps and Tools to accelerate Training. 74 | :col_css: col-md-6 75 | :button_link: training_studio.html 76 | :height: 180 77 | 78 | .. raw:: html 79 | 80 |
81 | 82 | .. raw:: html 83 | 84 |
85 | 86 | ---- 87 | 88 | *************** 89 | Troubleshooting 90 | *************** 91 | 92 | .. note:: On MacOS, if you face an OSError: Too many open files, you can increase your Mac process limit with: **ulimit -Sn 50000** 93 | -------------------------------------------------------------------------------- /docs/source/installation_mac.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | ################################## 4 | Installation on Apple Silicon Macs 5 | ################################## 6 | 7 | Apple Silicon (M1, M2, M3) Mac environments need a bit of tweaking before you install. 8 | 9 | ---- 10 | 11 | **************** 12 | Install with pip 13 | **************** 14 | 15 | Install the ``lightning`` package 16 | 17 | .. code:: bash 18 | 19 | export GRPC_PYTHON_BUILD_SYSTEM_OPENSSL=1 20 | export GRPC_PYTHON_BUILD_SYSTEM_ZLIB=1 21 | 22 | pip install lightning 23 | -------------------------------------------------------------------------------- /docs/source/installation_win.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | ####################### 4 | Installation on Windows 5 | ####################### 6 | 7 | We strongly recommend to create a virtual environment first. 8 | Don't know what this is? Follow our `beginner guide here `_. 9 | 10 | Windows environments might need a little more tweaking before you install. 11 | 12 | **Requirements** 13 | 14 | * Python 3.8.x or later (3.8.x, 3.9.x, 3.10.x) 15 | * Pip (the latest versions of Python will already have this) 16 | * Git 17 | * PyTorch - https://pytorch.org/get-started/locally/ 18 | * Setup an alias for Python: python=python3 19 | * Add the root folder of Lightning to the Environment Variables to PATH 20 | * Install Z shell (zsh) (This is required for Windows to install the quickstart app) 21 | 22 | ---- 23 | 24 | **************** 25 | Install with pip 26 | **************** 27 | 28 | 0. Activate your virtual environment. 29 | 30 | 1. Install the ``lightning`` package 31 | 32 | .. code:: bash 33 | 34 | python -m pip install -U lightning 35 | -------------------------------------------------------------------------------- /docs/source/more_examples/llms.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | ##################### 4 | Large Language Models 5 | ##################### 6 | 7 | .. _llms: 8 | 9 | .. join_slack:: 10 | :align: left 11 | 12 | ---- 13 | 14 | .. lit_tabs:: 15 | :titles: 1. Setup Lightning minGPT; 2. Run an experiment; 3. Scale the model size 16 | :code_files: llms/clone.bash; llms/experiment.bash; llms/scale.bash 17 | :works: 18 | :enable_run: false 19 | :tab_rows: 3 20 | :height: 540px 21 | -------------------------------------------------------------------------------- /docs/source/more_examples/llms/clone.bash: -------------------------------------------------------------------------------- 1 | # 1. Clone Lightning minGPT inspired from Andrej Karpathy's 2 | git clone https://github.com/Lightning-AI/lightning-gpt 3 | 4 | # 2. Enter the folder 5 | cd lightning-gpt 6 | 7 | # 3. Install the requirements 8 | pip install -r requirements.txt 9 | -------------------------------------------------------------------------------- /docs/source/more_examples/llms/experiment.bash: -------------------------------------------------------------------------------- 1 | # Run default minGPT with 85.3 M parameters on a single GPU 2 | lightning run experiment train.py \ 3 | --name="lightning-gpt-2" \ 4 | --cloud_compute="gpu-fast" 5 | 6 | # Run default minGPT with 85.3 M parameters using DeepSpeed on a single GPU 7 | lightning run experiment train.py \ 8 | --name="lightning-gpt-2-deepspeed" \ 9 | --cloud_compute="gpu-fast" \ 10 | --requirements="requirements-deepspeed.txt" \ 11 | --implementation="deepspeed" 12 | 13 | # Run default minGPT with 85.3 M parameters using optimized xFormers layers on a single GPU 14 | lightning run experiment train.py \ 15 | --name="lightning-gpt-2-xformers" \ 16 | --cloud_compute="gpu-fast" \ 17 | --requirements="requirements-xformers.txt" \ 18 | --implementation="xformers" 19 | -------------------------------------------------------------------------------- /docs/source/more_examples/llms/scale.bash: -------------------------------------------------------------------------------- 1 | # Run 1.4 Billion parameters model on 4 GPUS 2 | lightning run experiment train.py \ 3 | --name="lightning-gpt2-xl" \ 4 | --model_type="gpt2-xl" \ 5 | --batch_size=64 \ 6 | --cloud_compute="gpu-fast-multi" 7 | 8 | # Run 2.9 Billion parameters model on 4 GPUS 9 | lightning run experiment train.py \ 10 | --name="lightning-gpt2-xxl" \ 11 | --model_type="gpt2-xxl" \ 12 | --requirements="requirements-deepspeed.txt" \ 13 | --batch_size=16 \ 14 | --cloud_compute="gpu-fast-multi" \ 15 | --strategy="deepspeed_stage_3_offload" 16 | -------------------------------------------------------------------------------- /docs/source/setup/connect.bash: -------------------------------------------------------------------------------- 1 | # 1. Find the name of your App 2 | 3 | # Go to your Profile. 4 | # Then open the Training Studio App you have just cloned. 5 | # The App name is located on at the top /left 6 | # in the format {USERNAME}/Apps/{APP_NAME}. 7 | 8 | # Example: {tchaton}/Apps/{lightning/training-studio} 9 | 10 | # 2. Connect to your App as follows: 11 | # lightning connect {APP_NAME} -y 12 | lightning connect lightning/training-studio 13 | -------------------------------------------------------------------------------- /docs/source/setup/duplicate.bash: -------------------------------------------------------------------------------- 1 | # 1. Open the Training Studio App on the App Gallery 2 | open https://lightning.ai/app/hvUwbEG90B-Training%20studio 3 | 4 | # 2. Click the duplicate button 5 | -------------------------------------------------------------------------------- /docs/source/setup/pip.bash: -------------------------------------------------------------------------------- 1 | # Create a virtual env, install pip 2 | pip install -U lightning-training-studio 3 | -------------------------------------------------------------------------------- /docs/source/workflows/convert_from_raw_optuna.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | ####################### 4 | Convert from raw Optuna 5 | ####################### 6 | 7 | .. _convert_from_raw_optuna: 8 | 9 | .. join_slack:: 10 | :align: left 11 | 12 | ---- 13 | 14 | ************************ 15 | 1. Your Optuna Objective 16 | ************************ 17 | 18 | We are going to convert `Optuna Efficient Optimization Algorithms `_ into a Lightning App. 19 | 20 | This Optuna example optimizes the value (for example: learning-rate) of a ``SGDClassifier`` from ``sklearn`` trained over the `Iris Dataset `_. 21 | 22 | The example below is going to be re-organized as a Lightning App. 23 | 24 | .. literalinclude:: scripts/optuna_pruning.py 25 | 26 | ---- 27 | 28 | *************************** 29 | 2. Convert to Lightning HPO 30 | *************************** 31 | 32 | Import ``Sweep`` and ``Objective`` components and move your Optuna code within the objective method of your custom Objective. 33 | 34 | Add Imports 35 | ^^^^^^^^^^^ 36 | 37 | .. literalinclude:: ../../../sweep_examples/3_app_sklearn.py 38 | :lines: 1-9 39 | 40 | Implement the CustomObjective 41 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 42 | 43 | To customize an ``Objective``, you need to override the ``objective`` and pass all your hyper-parameters. 44 | 45 | The core difference from the previous scripts are: 46 | 47 | - ``self.monitor``: This is used to automatically populate metrics with your selected logger 48 | - ``self.reports``: Lightning HPO automatically takes care of pruning the experiments, simply register the step based reports. 49 | - ``self.best_model_score``: Lightning HPO expects you to register the best mode score of your model in the ``Objective`` state. 50 | 51 | .. literalinclude:: ../../../sweep_examples/3_app_sklearn.py 52 | :lines: 12-36 53 | 54 | Configure your Sweep 55 | ^^^^^^^^^^^^^^^^^^^^ 56 | 57 | Finally, you can define your ``Sweep`` and pass it an ``OptunaAlgorithm`` 58 | 59 | .. literalinclude:: ../../../sweep_examples/3_app_sklearn.py 60 | :lines: 39- 61 | 62 | ---- 63 | 64 | ************************** 65 | 3. Optimize your objective 66 | ************************** 67 | 68 | Now, you can optimize it locally. 69 | 70 | .. code-block:: 71 | 72 | python -m lightning run app sweep_examples/1_app_agnostic.py 73 | 74 | or with ``--cloud`` to run it in the cloud. 75 | 76 | .. code-block:: 77 | 78 | python -m lightning run app sweep_examples/1_app_agnostic.py --cloud 79 | 80 | .. note:: Locally, each experiment runs in its own process, so there is overhead if your objective is quick to run. 81 | -------------------------------------------------------------------------------- /docs/source/workflows/loggers.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | ###################### 4 | Configure your loggers 5 | ###################### 6 | 7 | .. _configure_your_logger: 8 | 9 | .. join_slack:: 10 | :align: left 11 | 12 | ---- 13 | 14 | ***************** 15 | Supported Loggers 16 | ***************** 17 | 18 | .. raw:: html 19 | 20 |
21 |
22 |
23 | 24 | .. displayitem:: 25 | :header: Tensorboard 26 | :description: Learn how to use Tensorboard with HPO 27 | :col_css: col-md-4 28 | :button_link: loggers/tensorboard.html 29 | :height: 180 30 | 31 | .. displayitem:: 32 | :header: StreamLit HiPlot 33 | :description: Learn how to use StreamLit with HPO 34 | :col_css: col-md-4 35 | :button_link: loggers/streamlit.html 36 | :height: 180 37 | 38 | .. displayitem:: 39 | :header: Wandb 40 | :description: Learn how to use Wandb with HPO 41 | :col_css: col-md-4 42 | :button_link: loggers/wandb.html 43 | :height: 180 44 | 45 | .. raw:: html 46 | 47 |
48 |
49 | -------------------------------------------------------------------------------- /docs/source/workflows/loggers/streamlit.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | ####################### 4 | StreamLit HiPlot Logger 5 | ####################### 6 | 7 | .. _streamlit_logger: 8 | 9 | .. join_slack:: 10 | :align: left 11 | 12 | ---- 13 | 14 | Simply add ``logger=streamlit`` to the ``Sweep`` component. 15 | 16 | .. code-block:: python 17 | 18 | from lightning_training_studio import Sweep 19 | 20 | Sweep(..., logger="streamlit") 21 | 22 | And Lightning HPO handles the rest: 23 | 24 | .. figure:: https://pl-flash-data.s3.amazonaws.com/assets_lightning/lightning_training_studio_optimizer.png 25 | :alt: StreamLit HiPlot 26 | :width: 100 % 27 | -------------------------------------------------------------------------------- /docs/source/workflows/loggers/tensorboard.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | ################## 4 | Tensorboard Logger 5 | ################## 6 | 7 | .. _tensorboard_logger: 8 | 9 | .. join_slack:: 10 | :align: left 11 | 12 | ---- 13 | 14 | Simply add ``logger=tensorboard`` to the ``Sweep`` component. 15 | 16 | .. code-block:: python 17 | 18 | from lightning_training_studio import Sweep 19 | 20 | Sweep(..., logger="tensorboard") 21 | 22 | And Lightning HPO handles the rest: 23 | 24 | .. figure:: https://pl-flash-data.s3.amazonaws.com/assets_lightning/tensorboard_sweep.png 25 | :alt: Tensorboard Logger 1 26 | :width: 100 % 27 | 28 | .. figure:: https://pl-flash-data.s3.amazonaws.com/assets_lightning/tensorboard_sweep_2.png 29 | :alt: Tensorboard Logger 2 30 | :width: 100 % 31 | -------------------------------------------------------------------------------- /docs/source/workflows/loggers/wandb.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | ############ 4 | Wandb Logger 5 | ############ 6 | 7 | .. _wandb_logger: 8 | 9 | .. join_slack:: 10 | :align: left 11 | 12 | ---- 13 | 14 | **************************************** 15 | 1. Pass the logger argument to the Sweep 16 | **************************************** 17 | 18 | .. code-block:: python 19 | 20 | from lightning_training_studio import Sweep 21 | 22 | Sweep(..., logger="wandb") 23 | 24 | 25 | *********************************** 26 | 2. Setup your environment variables 27 | *********************************** 28 | 29 | You can either setup the ``WANDB_ENTITY`` and ``WANDB_API_KEY`` and run the App: 30 | 31 | .. code-block:: 32 | 33 | export WANDB_ENTITY=... 34 | export WANDB_API_KEY=... 35 | lightning run app app.py 36 | 37 | Or pass them through the CLI: 38 | 39 | .. code-block:: 40 | 41 | lightning run app app.py WANDB_ENTITY=... --env WANDB_API_KEY=... 42 | 43 | *************************** 44 | 3. Check your Wandb Account 45 | *************************** 46 | 47 | Lightning HPO automatically generates a Sweep Report and organizes your runs, so everything is a single place. 48 | 49 | .. figure:: https://pl-flash-data.s3.amazonaws.com/assets_lightning/wandb2.png 50 | :alt: Wandb 51 | :width: 100 % 52 | -------------------------------------------------------------------------------- /docs/source/workflows/optimize_an_objective.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | ##################### 4 | Optimize an Objective 5 | ##################### 6 | 7 | .. _optimize_an_objective: 8 | 9 | .. join_slack:: 10 | :align: left 11 | 12 | ---- 13 | 14 | .. include:: optimize_an_objective_context.rst 15 | -------------------------------------------------------------------------------- /docs/source/workflows/optimize_an_objective_context.rst: -------------------------------------------------------------------------------- 1 | ************************ 2 | 1. Define your objective 3 | ************************ 4 | 5 | Imagine you want to optimize a simple function called ``objective`` inside an ``objective.py`` file. 6 | 7 | .. literalinclude:: ../../../sweep_examples/scripts/objective.py 8 | 9 | ---- 10 | 11 | ******************** 12 | 2. Define your Sweep 13 | ******************** 14 | 15 | Import a ``Sweep`` component and provide the path to your script and what you want to optimize on. 16 | 17 | .. literalinclude:: ../../../sweep_examples/1_app_agnostic.py 18 | 19 | ---- 20 | 21 | ************************** 22 | 3. Optimize your objective 23 | ************************** 24 | 25 | Now, you can optimize it locally. 26 | 27 | .. code-block:: 28 | 29 | python -m lightning run app sweep_examples/1_app_agnostic.py 30 | 31 | or with ``--cloud`` to run it in the cloud. 32 | 33 | .. code-block:: 34 | 35 | python -m lightning run app sweep_examples/1_app_agnostic.py --cloud 36 | 37 | .. note:: Locally, each experiment runs in its own process, so there is overhead if your objective is quick to run. 38 | -------------------------------------------------------------------------------- /docs/source/workflows/run_notebook.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | ############## 4 | Run a Notebook 5 | ############## 6 | 7 | .. _run_notebook: 8 | 9 | .. join_slack:: 10 | :align: left 11 | 12 | ---- 13 | 14 | ************************** 15 | 1. Check available options 16 | ************************** 17 | 18 | The Training Studio App CLI provides its own help. 19 | 20 | .. code-block:: 21 | 22 | lightning run notebook --help 23 | 24 | Here is the output of the command: 25 | 26 | .. code-block:: 27 | 28 | You are connected to the local Lightning App. 29 | usage: notebook [-h] [--name NAME] [--requirements REQUIREMENTS [REQUIREMENTS ...]] 30 | [--cloud_compute CLOUD_COMPUTE] 31 | 32 | optional arguments: 33 | -h, --help show this help message and exit 34 | --name NAME The name of your notebook to run. 35 | --requirements REQUIREMENTS [REQUIREMENTS ...] 36 | Requirements file. 37 | --cloud_compute CLOUD_COMPUTE 38 | The machine to use in the cloud. 39 | 40 | ---- 41 | 42 | ***************** 43 | 2. Run a Notebook 44 | ***************** 45 | 46 | You can simply start a notebook as follows: 47 | 48 | .. code-block:: 49 | 50 | lightning run notebook --name=my_notebook 51 | 52 | .. code-block:: 53 | 54 | You are connected to the local Lightning App. 55 | The notebook `my_notebook` has been created. 56 | Your command execution was successful 57 | 58 | ---- 59 | 60 | ********** 61 | Next Steps 62 | ********** 63 | 64 | .. raw:: html 65 | 66 |
67 |
68 |
69 | 70 | .. displayitem:: 71 | :header: Show Notebooks 72 | :description: Learn how to view the existing notebooks 73 | :col_css: col-md-4 74 | :button_link: show_notebooks.html 75 | :height: 180 76 | 77 | .. displayitem:: 78 | :header: Stop or delete a Notebook 79 | :description: Learn how to stop or delete an existing notebook 80 | :col_css: col-md-4 81 | :button_link: stop_or_delete_notebook.html 82 | :height: 180 83 | 84 | .. displayitem:: 85 | :header: Run a Sweep 86 | :description: Learn how to run a Sweep with your own python script 87 | :col_css: col-md-4 88 | :button_link: run_sweep.html 89 | :height: 180 90 | 91 | 92 | .. raw:: html 93 | 94 |
95 |
96 | -------------------------------------------------------------------------------- /docs/source/workflows/scripts/optuna_pruning.py: -------------------------------------------------------------------------------- 1 | import optuna 2 | import sklearn.datasets 3 | import sklearn.linear_model 4 | import sklearn.model_selection 5 | 6 | 7 | def objective(trial: optuna.Trial): 8 | # 1. Download the dataset and prepare the data 9 | iris = sklearn.datasets.load_iris() 10 | classes = list(set(iris.target)) 11 | train_x, valid_x, train_y, valid_y = sklearn.model_selection.train_test_split( 12 | iris.data, iris.target, test_size=0.25, random_state=0 13 | ) 14 | 15 | # 2: Sample alpha from the Trial 16 | alpha = trial.suggest_float("alpha", 1e-5, 1e-1, log=True) 17 | 18 | # 3: Create a SGDClassifier 19 | clf = sklearn.linear_model.SGDClassifier(alpha=alpha) 20 | 21 | # 4. Optimize for 100 steps 22 | for step in range(100): 23 | # 4.1 Fit the classifier on the training data 24 | clf.partial_fit(train_x, train_y, classes=classes) 25 | 26 | # 4.2 Report intermediate objective value. 27 | # If the model doesn't converge, the trial would be pruned (e.g killed) 28 | intermediate_value = 1.0 - clf.score(valid_x, valid_y) 29 | trial.report(intermediate_value, step) 30 | 31 | # 4.3 Manually prune the trial 32 | if trial.should_prune(): 33 | raise optuna.TrialPruned() 34 | 35 | # 5. Return the score to be optimized 36 | return 1.0 - clf.score(valid_x, valid_y) 37 | 38 | 39 | if __name__ == "__main__": 40 | # 6. Create an Optuna Study with a median pruner. 41 | # All trials below the median are pruned. 42 | study = optuna.create_study(pruner=optuna.pruners.MedianPruner()) 43 | 44 | # 7. Launch 20 trials 45 | study.optimize(objective, n_trials=20) 46 | -------------------------------------------------------------------------------- /docs/source/workflows/show_notebooks.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | ############## 4 | Show Notebooks 5 | ############## 6 | 7 | .. _show_sweeps: 8 | 9 | .. join_slack:: 10 | :align: left 11 | 12 | ---- 13 | 14 | In order to view your notebooks, use this command: 15 | 16 | .. code-block:: 17 | 18 | lightning show notebooks 19 | 20 | Here is the output of the command: 21 | 22 | .. code-block:: 23 | 24 | You are connected to the local Lightning App. 25 | Notebooks 26 | ┳━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓ 27 | ┃ name ┃ stage ┃ desired_stage ┃ cloud_compute ┃ requirements ┃ 28 | ╇━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━┩ 29 | │ notebook_2 │ stopped │ stopped │ cpu │ [] │ 30 | │ my_notebook │ running │ running │ cpu │ [] │ 31 | ┴─────────────┴─────────┴────────────────┴───────────────┴──────────────┘ 32 | 33 | ---- 34 | 35 | ********** 36 | Next Steps 37 | ********** 38 | 39 | .. raw:: html 40 | 41 |
42 |
43 |
44 | 45 | .. displayitem:: 46 | :header: Stop or delete a Notebook 47 | :description: Learn how to stop or delete an existing notebook 48 | :col_css: col-md-4 49 | :button_link: stop_or_delete_notebook.html 50 | :height: 180 51 | 52 | .. displayitem:: 53 | :header: Run a Sweep 54 | :description: Learn how to run a Sweep with your own python script 55 | :col_css: col-md-4 56 | :button_link: run_sweep.html 57 | :height: 180 58 | 59 | .. displayitem:: 60 | :header: Show or Download Artifacts 61 | :description: Learn how to interact with your Training Studio App artifacts 62 | :col_css: col-md-4 63 | :button_link: show_or_download_artifacts.html 64 | :height: 180 65 | 66 | .. raw:: html 67 | 68 |
69 |
70 | -------------------------------------------------------------------------------- /docs/source/workflows/show_or_download_logs.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | ##################### 4 | Show or download logs 5 | ##################### 6 | 7 | .. _run_sweep: 8 | 9 | .. join_slack:: 10 | :align: left 11 | 12 | ---- 13 | 14 | ************************** 15 | 1. Check available options 16 | ************************** 17 | 18 | The Training Studio App CLI provides its own help. 19 | 20 | .. code-block:: 21 | 22 | lightning show logs --help 23 | 24 | Here is the output of the command: 25 | 26 | .. code-block:: 27 | 28 | Usage: lightning show logs [OPTIONS] [APP_NAME] [COMPONENTS]... 29 | 30 | Show cloud application logs. By default prints logs for all currently 31 | available components. 32 | 33 | Example uses: 34 | 35 | Print all application logs: 36 | 37 | $ lightning show logs my-application 38 | 39 | Print logs only from the flow (no work): 40 | 41 | $ lightning show logs my-application flow 42 | 43 | Print logs only from selected works: 44 | 45 | $ lightning show logs my-application root.work_a root.work_b 46 | 47 | Options: 48 | -f, --follow Wait for new logs, to exit use CTRL+C. 49 | --help Show this message and exit. 50 | 51 | 52 | ************ 53 | 2. Show logs 54 | ************ 55 | 56 | To view the logs use the following command: 57 | 58 | .. code-block:: 59 | 60 | lightning show logs training_studio_app 61 | 62 | .. note:: You get logs only once the Lightning App is ready. Wait for the Open App button to be visible. 63 | 64 | **************** 65 | 3. Download logs 66 | **************** 67 | 68 | You can simply download the logs by piping them within a ``log.txt`` file: 69 | 70 | .. code-block:: 71 | 72 | lightning show logs training_studio_app > logs.txt 73 | 74 | ---- 75 | 76 | ********** 77 | Next Steps 78 | ********** 79 | 80 | .. raw:: html 81 | 82 |
83 |
84 |
85 | 86 | .. displayitem:: 87 | :header: Show or Download Artifacts 88 | :description: Learn how to interact with your Training Studio App artifacts 89 | :col_css: col-md-4 90 | :button_link: show_or_download_artifacts.html 91 | :height: 180 92 | 93 | 94 | .. displayitem:: 95 | :header: Run a Sweep 96 | :description: Learn how to run a Sweep with your own python script 97 | :col_css: col-md-4 98 | :button_link: run_sweep.html 99 | :height: 180 100 | 101 | .. displayitem:: 102 | :header: Run a Notebook 103 | :description: Learn how to run a notebook locally or in the cloud 104 | :col_css: col-md-4 105 | :button_link: run_notebook.html 106 | :height: 180 107 | 108 | .. raw:: html 109 | 110 |
111 |
112 | -------------------------------------------------------------------------------- /docs/source/workflows/stop_or_delete_notebook.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | ######################## 4 | Stop or delete Notebooks 5 | ######################## 6 | 7 | .. _show_notebooks: 8 | 9 | .. join_slack:: 10 | :align: left 11 | 12 | ---- 13 | 14 | *************** 15 | Stop a Notebook 16 | *************** 17 | 18 | To stop a notebook use the following command: 19 | 20 | .. code-block:: 21 | 22 | lightning stop notebook --name=my_notebook_name 23 | 24 | Here is the output of the command: 25 | 26 | .. code-block:: 27 | 28 | You are connected to the local Lightning App. 29 | The notebook `my_notebook_name` has been stopped. 30 | Your command execution was successful. 31 | 32 | ---- 33 | 34 | ***************** 35 | Delete a Notebook 36 | ***************** 37 | 38 | TODO 39 | 40 | ---- 41 | 42 | ********** 43 | Next Steps 44 | ********** 45 | 46 | .. raw:: html 47 | 48 |
49 |
50 |
51 | 52 | .. displayitem:: 53 | :header: Run a Sweep 54 | :description: Learn how to run a Sweep with your own python script 55 | :col_css: col-md-4 56 | :button_link: run_sweep.html 57 | :height: 180 58 | 59 | .. displayitem:: 60 | :header: Show or Download Artifacts 61 | :description: Learn how to interact with your Training Studio App artifacts 62 | :col_css: col-md-4 63 | :button_link: show_or_download_artifacts.html 64 | :height: 180 65 | 66 | .. displayitem:: 67 | :header: Show or Download Logs 68 | :description: Learn how to interact with your Training Studio App logs 69 | :col_css: col-md-4 70 | :button_link: show_or_download_logs.html 71 | :height: 180 72 | 73 | .. raw:: html 74 | 75 |
76 |
77 | -------------------------------------------------------------------------------- /docs/source/workflows/stop_or_delete_sweep.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | ###################### 4 | Stop or delete a Sweep 5 | ###################### 6 | 7 | .. _stop_sweep: 8 | 9 | .. join_slack:: 10 | :align: left 11 | 12 | ---- 13 | 14 | ***************** 15 | Stop a Experiment 16 | ***************** 17 | 18 | To stop a experiment use the following commnand: 19 | 20 | .. code-block:: 21 | 22 | lightning stop experiment --name= 23 | 24 | For example: 25 | 26 | .. code-block:: 27 | 28 | lightning stop sweep --name=29f40d6 29 | 30 | Here is the output of the command: 31 | 32 | .. code-block:: 33 | 34 | You are connected to the local Lightning App. 35 | Stopped the experiment `29f40d6` 36 | Your command execution was successful 37 | 38 | ---- 39 | 40 | ************ 41 | Stop a Sweep 42 | ************ 43 | 44 | To stop a sweep use the following commnand: 45 | 46 | .. code-block:: 47 | 48 | lightning stop sweep --name= 49 | 50 | For example: 51 | 52 | .. code-block:: 53 | 54 | lightning stop sweep --name=thomas-0f615232 55 | 56 | Here is the output of the command: 57 | 58 | .. code-block:: 59 | 60 | You are connected to the local Lightning App. 61 | Stopped the sweep `thomas-0f615232` 62 | Your command execution was successful 63 | 64 | ---- 65 | 66 | ************** 67 | Delete a Sweep 68 | ************** 69 | 70 | To delete a sweep use the following command: 71 | 72 | .. code-block:: 73 | 74 | lightning delete sweep --name= 75 | 76 | For example: 77 | 78 | .. code-block:: 79 | 80 | lightning delete sweep --name=thomas-0f615232 81 | 82 | ---- 83 | 84 | ********** 85 | Next Steps 86 | ********** 87 | 88 | .. raw:: html 89 | 90 |
91 |
92 |
93 | 94 | .. displayitem:: 95 | :header: Run a Notebook 96 | :description: Learn how to run a notebook locally or in the cloud 97 | :col_css: col-md-4 98 | :button_link: run_notebook.html 99 | :height: 180 100 | 101 | .. displayitem:: 102 | :header: Show or Download Artifacts 103 | :description: Learn how to interact with your Training Studio App artifacts 104 | :col_css: col-md-4 105 | :button_link: show_or_download_artifacts.html 106 | :height: 180 107 | 108 | .. displayitem:: 109 | :header: Show or Download Logs 110 | :description: Learn how to interact with your Training Studio App logs 111 | :col_css: col-md-4 112 | :button_link: show_or_download_logs.html 113 | :height: 180 114 | 115 | .. raw:: html 116 | 117 |
118 |
119 | -------------------------------------------------------------------------------- /docs/source/workflows/sweep.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | ########### 4 | Run a Sweep 5 | ########### 6 | 7 | .. _run_a_sweep: 8 | 9 | A **sweep** is a collection of experiments where hyper-parameters are modified by an algorithm to optimize your objective. 10 | 11 | .. join_slack:: 12 | :align: left 13 | 14 | ---- 15 | 16 | .. include:: optimize_an_objective_context.rst 17 | -------------------------------------------------------------------------------- /lightning_training_studio/__about__.py: -------------------------------------------------------------------------------- 1 | __version__ = "0.0.3" 2 | __author__ = "PyTorchLightning et al." 3 | __author_email__ = "thomas@grid.ai" 4 | __license__ = "TBD" 5 | __copyright__ = f"Copyright (c) 2021-2022, {__author__}." 6 | __homepage__ = "https://github.com/PyTorchLightning/lightning" 7 | __docs__ = "Lightning HPO" 8 | __long_doc__ = """ 9 | The Lightning PyTorch Training Studio App provides a pythonic implementation for Scalable Hyperparameter Tuning. 10 | This library relies on Optuna for providing state-of-the-art sampling hyper-parameters algorithms 11 | and efficient experiment pruning strategies. 12 | """ 13 | 14 | __all__ = [ 15 | "__author__", 16 | "__author_email__", 17 | "__copyright__", 18 | "__docs__", 19 | "__homepage__", 20 | "__license__", 21 | "__version__", 22 | ] 23 | -------------------------------------------------------------------------------- /lightning_training_studio/__init__.py: -------------------------------------------------------------------------------- 1 | """Root package info.""" 2 | import logging 3 | import os 4 | 5 | _root_logger = logging.getLogger() 6 | _logger = logging.getLogger(__name__) 7 | _logger.setLevel(logging.INFO) 8 | 9 | _console = logging.StreamHandler() 10 | _console.setLevel(logging.INFO) 11 | 12 | formatter = logging.Formatter("%(levelname)s: %(message)s") 13 | _console.setFormatter(formatter) 14 | 15 | # if root logger has handlers, propagate messages up and let root logger process them, 16 | # otherwise use our own handler 17 | if not _root_logger.hasHandlers(): 18 | _logger.addHandler(_console) 19 | _logger.propagate = False 20 | 21 | from lightning_training_studio.__about__ import * # noqa: E402, F401, F403 22 | from lightning_training_studio.components.sweep import Sweep # noqa: E402 23 | from lightning_training_studio.framework.agnostic import Objective # noqa: E402 24 | from lightning_training_studio.utilities.utils import HPOCloudCompute # noqa: E402, F401 25 | 26 | _PACKAGE_ROOT = os.path.dirname(__file__) 27 | _PROJECT_ROOT = os.path.dirname(_PACKAGE_ROOT) 28 | 29 | from optuna.storages._in_memory import _logger # noqa: E501 E402 30 | 31 | _logger.disabled = True 32 | _logger.propagate = False 33 | 34 | __all__ = ["Objective", "Sweep", "HPOCloudCompute"] 35 | -------------------------------------------------------------------------------- /lightning_training_studio/algorithm/__init__.py: -------------------------------------------------------------------------------- 1 | from lightning_training_studio.algorithm.optuna import GridSearch, OptunaAlgorithm, RandomSearch 2 | 3 | __all__ = ["OptunaAlgorithm", "GridSearch", "RandomSearch"] 4 | -------------------------------------------------------------------------------- /lightning_training_studio/algorithm/base.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | from typing import Any, Dict, List 3 | 4 | from lightning_training_studio.commands.sweep.run import ExperimentConfig 5 | 6 | 7 | class Algorithm(ABC): 8 | @abstractmethod 9 | def register_distributions(self, distributions): 10 | ... 11 | 12 | @abstractmethod 13 | def register_experiments(self, experiments: List[ExperimentConfig]): 14 | ... 15 | 16 | @abstractmethod 17 | def experiment_start(self, experiment_id: int): 18 | ... 19 | 20 | @abstractmethod 21 | def experiment_end(self, experiment_id: int, score: float): 22 | ... 23 | 24 | @abstractmethod 25 | def should_prune(self, experiment_id: int, reports: List[float]) -> bool: 26 | ... 27 | 28 | @abstractmethod 29 | def get_params(self, experiment_id: int) -> Dict[str, Any]: 30 | ... 31 | -------------------------------------------------------------------------------- /lightning_training_studio/app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/lightning_training_studio/app/__init__.py -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "jsxSingleQuote": false, 3 | "arrowParens": "avoid", 4 | "tabWidth": 2, 5 | "useTabs": false, 6 | "printWidth": 119, 7 | "singleQuote": true, 8 | "semi": true, 9 | "endOfLine": "lf", 10 | "proseWrap": "always", 11 | "bracketSameLine": true, 12 | "quoteProps": "consistent", 13 | "trailingComma": "all", 14 | "bracketSpacing": true 15 | } 16 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/README.md: -------------------------------------------------------------------------------- 1 | # Training Studio App UI 2 | 3 | This guide explains the process of: installing the dependencies for, building, and developing the Training Studio App React UI. 4 | 5 | ## Installing Dependencies 6 | 7 | Before you can build the UI, you will need to install: 8 | 9 | - [node.js](https://nodejs.org/en/) 10 | - [yarn](https://yarnpkg.com/getting-started/install) 11 | 12 | Once you have yarn installed, you can install the dependencies for this project by running (from the `lightning_training_studio/app/ui` folder): 13 | 14 | ```bash 15 | yarn install 16 | ``` 17 | 18 | ## Building the UI 19 | 20 | To build the UI, run: 21 | 22 | ```bash 23 | yarn run build 24 | ``` 25 | 26 | ## Running the App 27 | 28 | To run the app with the react UI, use: 29 | 30 | ```bash 31 | REACT_UI=1 lightning run app ... 32 | ``` 33 | 34 | **Note: You can rebuild the UI and refresh the app page without stopping the app.** 35 | 36 | ## Updating the App Client 37 | 38 | If the app REST API changes, update `spec.json` to the new openapi spec and re-generate the client with: 39 | 40 | ```bash 41 | yarn run generate 42 | ``` 43 | 44 | ## Live Building 45 | 46 | If you want the UI to live update, run: 47 | 48 | ```bash 49 | yarn run start 50 | ``` 51 | 52 | **Note: This is not generally recommended as it can be quite resource intensive.** 53 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/build/asset-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": { 3 | "main.css": "/static/css/main.bbbac2be.css", 4 | "main.js": "/static/js/main.7b96e885.js", 5 | "static/js/787.9615c779.chunk.js": "/static/js/787.9615c779.chunk.js", 6 | "static/media/UCity-Regular.woff": "/static/media/UCity-Regular.7a3b475525ed92dc7816.woff", 7 | "static/media/UCity-Light.woff": "/static/media/UCity-Light.47cf3e33cb6bb1496c95.woff", 8 | "static/media/UCity-Semibold.woff": "/static/media/UCity-Semibold.bb7aab96e378ebd6a651.woff", 9 | "static/media/UCity-Regular.woff2": "/static/media/UCity-Regular.8afa44ac39706d62b62b.woff2", 10 | "static/media/UCity-Light.woff2": "/static/media/UCity-Light.30446c15a21bf8a994e8.woff2", 11 | "static/media/UCity-Semibold.woff2": "/static/media/UCity-Semibold.80655a0e8b4bb5f30545.woff2", 12 | "static/media/cloud.svg": "/static/media/cloud.7aee0ddfc3bf81079995a22e719e53fb.svg", 13 | "static/media/warning.svg": "/static/media/warning.5c542673e84e77ceb6a230bfea7f7263.svg", 14 | "index.html": "/index.html", 15 | "static/media/error.svg": "/static/media/error.11892047d0183a4723b91dc0fb98cb95.svg", 16 | "static/media/success.svg": "/static/media/success.5edae4c5b171e2c1c5a3c54273c47ba8.svg", 17 | "main.bbbac2be.css.map": "/static/css/main.bbbac2be.css.map", 18 | "main.7b96e885.js.map": "/static/js/main.7b96e885.js.map", 19 | "787.9615c779.chunk.js.map": "/static/js/787.9615c779.chunk.js.map" 20 | }, 21 | "entrypoints": [ 22 | "static/css/main.bbbac2be.css", 23 | "static/js/main.7b96e885.js" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/build/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/build/index.html: -------------------------------------------------------------------------------- 1 | Lightning Training Studio
2 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/build/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Training Studio", 3 | "name": "Lightning Training Studio", 4 | "icons": [ 5 | { 6 | "src": "favicon.svg", 7 | "sizes": "512x512 192x192 64x64 32x32 24x24 16x16", 8 | "type": "image/svg+xml" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/build/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/build/static/css/main.bbbac2be.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css2?family=Roboto&family=Roboto+Mono&display=swap);@import url(https://fonts.googleapis.com/icon?family=Material+Icons);@font-face{font-display:"swap";font-family:UCity;font-weight:300;src:local("UCity Light"),url(static/media/UCity-Light.30446c15a21bf8a994e8.woff2) format("woff2"),url(static/media/UCity-Light.47cf3e33cb6bb1496c95.woff) format("woff")}@font-face{font-display:"swap";font-family:UCity;font-weight:400;src:local("UCity Regular"),url(static/media/UCity-Regular.8afa44ac39706d62b62b.woff2) format("woff2"),url(static/media/UCity-Regular.7a3b475525ed92dc7816.woff) format("woff")}@font-face{font-display:"swap";font-family:UCity;font-weight:600;src:local("UCity Semibold"),url(static/media/UCity-Semibold.80655a0e8b4bb5f30545.woff2) format("woff2"),url(static/media/UCity-Semibold.bb7aab96e378ebd6a651.woff) format("woff")}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;margin:0;overflow-y:overlay}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}pre{font-size:.8em;max-height:40em;overflow:scroll} 2 | /*# sourceMappingURL=main.bbbac2be.css.map*/ 3 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/build/static/css/main.bbbac2be.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"static/css/main.bbbac2be.css","mappings":"kKAGA,WAEE,mBAAoB,CADpB,iBAAoB,CAEpB,eAAgB,CAChB,wKAEF,CAEA,WAEE,mBAAoB,CADpB,iBAAoB,CAEpB,eAAgB,CAChB,8KAEF,CAEA,WAEE,mBAAoB,CADpB,iBAAoB,CAEpB,eAAgB,CAChB,iLAEF,CCzBA,KAGE,kCAAmC,CACnC,iCAAkC,CAFlC,yFAA+G,CAD/G,QAAS,CAIT,kBACF,CAEA,KACE,uEACF,CAEA,IAEE,cAAgB,CAChB,eAAgB,CAFhB,eAGF","sources":["../node_modules/lightning-ui/src/design-system/style.css","index.css"],"sourcesContent":["@import url(\"https://fonts.googleapis.com/css2?family=Roboto&family=Roboto+Mono&display=swap\");\n@import url(\"https://fonts.googleapis.com/icon?family=Material+Icons\");\n\n@font-face {\n font-family: \"UCity\";\n font-display: \"swap\";\n font-weight: 300;\n src: local(\"UCity Light\"), url(\"./fonts/UCity/UCity-Light.woff2\") format(\"woff2\"),\n url(\"./fonts/UCity/UCity-Light.woff\") format(\"woff\");\n}\n\n@font-face {\n font-family: \"UCity\";\n font-display: \"swap\";\n font-weight: 400;\n src: local(\"UCity Regular\"), url(\"./fonts/UCity/UCity-Regular.woff2\") format(\"woff2\"),\n url(\"./fonts/UCity/UCity-Regular.woff\") format(\"woff\");\n}\n\n@font-face {\n font-family: \"UCity\";\n font-display: \"swap\";\n font-weight: 600;\n src: local(\"UCity Semibold\"), url(\"./fonts/UCity/UCity-Semibold.woff2\") format(\"woff2\"),\n url(\"./fonts/UCity/UCity-Semibold.woff\") format(\"woff\");\n}\n","body {\n margin: 0;\n font-family: 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n overflow-y: overlay;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;\n}\n\npre {\n overflow: scroll;\n font-size: 0.8em;\n max-height: 40em;\n}\n\n@import 'lightning-ui/src/design-system/style.css';\n"],"names":[],"sourceRoot":""} 2 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/build/static/js/main.7b96e885.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* 2 | object-assign 3 | (c) Sindre Sorhus 4 | @license MIT 5 | */ 6 | 7 | /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */ 8 | 9 | /** 10 | * React Router v6.3.0 11 | * 12 | * Copyright (c) Remix Software Inc. 13 | * 14 | * This source code is licensed under the MIT license found in the 15 | * LICENSE.md file in the root directory of this source tree. 16 | * 17 | * @license MIT 18 | */ 19 | 20 | /** @license MUI v5.8.0 21 | * 22 | * This source code is licensed under the MIT license found in the 23 | * LICENSE file in the root directory of this source tree. 24 | */ 25 | 26 | /** @license React v0.20.2 27 | * scheduler.production.min.js 28 | * 29 | * Copyright (c) Facebook, Inc. and its affiliates. 30 | * 31 | * This source code is licensed under the MIT license found in the 32 | * LICENSE file in the root directory of this source tree. 33 | */ 34 | 35 | /** @license React v16.13.1 36 | * react-is.production.min.js 37 | * 38 | * Copyright (c) Facebook, Inc. and its affiliates. 39 | * 40 | * This source code is licensed under the MIT license found in the 41 | * LICENSE file in the root directory of this source tree. 42 | */ 43 | 44 | /** @license React v17.0.2 45 | * react-dom.production.min.js 46 | * 47 | * Copyright (c) Facebook, Inc. and its affiliates. 48 | * 49 | * This source code is licensed under the MIT license found in the 50 | * LICENSE file in the root directory of this source tree. 51 | */ 52 | 53 | /** @license React v17.0.2 54 | * react-is.production.min.js 55 | * 56 | * Copyright (c) Facebook, Inc. and its affiliates. 57 | * 58 | * This source code is licensed under the MIT license found in the 59 | * LICENSE file in the root directory of this source tree. 60 | */ 61 | 62 | /** @license React v17.0.2 63 | * react-jsx-runtime.production.min.js 64 | * 65 | * Copyright (c) Facebook, Inc. and its affiliates. 66 | * 67 | * This source code is licensed under the MIT license found in the 68 | * LICENSE file in the root directory of this source tree. 69 | */ 70 | 71 | /** @license React v17.0.2 72 | * react.production.min.js 73 | * 74 | * Copyright (c) Facebook, Inc. and its affiliates. 75 | * 76 | * This source code is licensed under the MIT license found in the 77 | * LICENSE file in the root directory of this source tree. 78 | */ 79 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/build/static/media/UCity-Light.30446c15a21bf8a994e8.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/lightning_training_studio/app/ui/build/static/media/UCity-Light.30446c15a21bf8a994e8.woff2 -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/build/static/media/UCity-Light.47cf3e33cb6bb1496c95.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/lightning_training_studio/app/ui/build/static/media/UCity-Light.47cf3e33cb6bb1496c95.woff -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/build/static/media/UCity-Regular.7a3b475525ed92dc7816.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/lightning_training_studio/app/ui/build/static/media/UCity-Regular.7a3b475525ed92dc7816.woff -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/build/static/media/UCity-Regular.8afa44ac39706d62b62b.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/lightning_training_studio/app/ui/build/static/media/UCity-Regular.8afa44ac39706d62b62b.woff2 -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/build/static/media/UCity-Semibold.80655a0e8b4bb5f30545.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/lightning_training_studio/app/ui/build/static/media/UCity-Semibold.80655a0e8b4bb5f30545.woff2 -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/build/static/media/UCity-Semibold.bb7aab96e378ebd6a651.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/lightning_training_studio/app/ui/build/static/media/UCity-Semibold.bb7aab96e378ebd6a651.woff -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/build/static/media/error.11892047d0183a4723b91dc0fb98cb95.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/build/static/media/success.5edae4c5b171e2c1c5a3c54273c47ba8.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/build/static/media/warning.5c542673e84e77ceb6a230bfea7f7263.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/craco.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const fs = require('fs'); 3 | const cracoBabelLoader = require('craco-babel-loader'); 4 | 5 | // manage relative paths to packages 6 | const appDirectory = fs.realpathSync(process.cwd()); 7 | const resolvePackage = relativePath => path.resolve(appDirectory, relativePath); 8 | 9 | const IS_DEV = process.env.NODE_ENV !== 'production'; 10 | 11 | const webpack = { 12 | configure: { 13 | output: { 14 | publicPath: './', 15 | }, 16 | }, 17 | }; 18 | 19 | module.exports = { 20 | ...(IS_DEV ? {} : { webpack }), 21 | devServer: { 22 | devMiddleware: { 23 | writeToDisk: true, 24 | }, 25 | }, 26 | plugins: [ 27 | { 28 | plugin: cracoBabelLoader, 29 | options: { 30 | includes: [resolvePackage('node_modules/lightning-ui')], 31 | }, 32 | }, 33 | ], 34 | }; 35 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 13 | 14 | 23 | Lightning Training Studio 24 | 25 | 49 | 50 | 51 | 52 |
53 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Training Studio", 3 | "name": "Lightning Training Studio", 4 | "icons": [ 5 | { 6 | "src": "favicon.svg", 7 | "sizes": "512x512 192x192 64x64 32x32 24x24 16x16", 8 | "type": "image/svg+xml" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/components/BorderLinearProgress.tsx: -------------------------------------------------------------------------------- 1 | import LinearProgress, { linearProgressClasses } from '@mui/material/LinearProgress'; 2 | import { styled } from '@mui/material/styles'; 3 | 4 | const BorderLinearProgress = styled(LinearProgress)(({ theme }) => ({ 5 | height: 8, 6 | borderRadius: 6, 7 | [`&.${linearProgressClasses.colorPrimary}`]: { 8 | backgroundColor: theme.palette.grey[theme.palette.mode === 'light' ? 200 : 800], 9 | }, 10 | [`& .${linearProgressClasses.bar}`]: { 11 | borderRadius: 6, 12 | backgroundColor: theme.palette.primary['main'], 13 | }, 14 | })); 15 | 16 | export default BorderLinearProgress; 17 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/components/DataTable.tsx: -------------------------------------------------------------------------------- 1 | import { DataConfig } from 'generated'; 2 | import useClientDataState from 'hooks/useClientDataState'; 3 | import useShowHelpPageState, { HelpPageState } from 'hooks/useShowHelpPageState'; 4 | import { Table } from 'lightning-ui/src/design-system/components'; 5 | import { getAppId } from 'utilities'; 6 | import UserGuide, { UserGuideBody, UserGuideComment } from './UserGuide'; 7 | 8 | const DataTable = () => { 9 | const { showHelpPage, setShowHelpPage } = useShowHelpPageState(); 10 | const data = useClientDataState('data') as DataConfig[]; 11 | 12 | const appId = getAppId(); 13 | 14 | if (data.length == 0) { 15 | setShowHelpPage(HelpPageState.forced); 16 | } else if (showHelpPage == HelpPageState.forced) { 17 | setShowHelpPage(HelpPageState.notShown); 18 | } 19 | 20 | if (showHelpPage == HelpPageState.forced || showHelpPage == HelpPageState.shown) { 21 | return ( 22 | 25 | Connect to the app 26 | {`lightning connect ${appId}`} 27 | Add a dataset by providing its name and s3 source location 28 | 29 | {'lightning add dataset --name mnist --source s3://lightning-example-public/MNIST/'} 30 | 31 | 32 | Run an experiment using the newly added mnist dataset. The data are visible under{' '} 33 | /content/data/MNIST/ 34 | 35 | {'lightning run experiment train.py --dataset mnist:/content/data/MNIST/'} 36 | 37 | ); 38 | } 39 | 40 | const header = ['Name', 'Source', 'Default Mount Path']; 41 | 42 | const rows = data.map(data => { 43 | return [data.name, data.source, data.mount_path]; 44 | }); 45 | 46 | return ; 47 | }; 48 | 49 | export default DataTable; 50 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/components/LightningToggleButtonGroup.tsx: -------------------------------------------------------------------------------- 1 | import { styled } from '@mui/material/styles'; 2 | import ToggleButtonGroup from '@mui/material/ToggleButtonGroup'; 3 | 4 | const LightningToggleButtonGroup = styled(ToggleButtonGroup)(({ theme }) => ({ 5 | '& .MuiToggleButtonGroup-grouped': { 6 | 'margin': theme.spacing(0.5), 7 | 'border': 0, 8 | 'borderRadius': 2, 9 | 'height': 28, 10 | 'gap': 8, 11 | 'padding': '4px 8px', 12 | 'color': '#5B5E69', 13 | 'backgroundColor': 'rgba(0, 0, 0, 0.1)', 14 | 'textTransform': 'none', 15 | '&.Mui-disabled': { 16 | border: 0, 17 | }, 18 | '&.Mui-selected': { 19 | color: theme.palette.primary['main'], 20 | backgroundColor: (theme.palette.primary as unknown as { '10': string })['10'], 21 | }, 22 | '&:first-of-type': { 23 | marginLeft: '0px', 24 | borderBottomLeftRadius: 20, 25 | borderTopLeftRadius: 20, 26 | }, 27 | '&:last-of-type': { 28 | marginRight: '0px', 29 | borderBottomRightRadius: 20, 30 | borderTopRightRadius: 20, 31 | }, 32 | }, 33 | })); 34 | 35 | export default LightningToggleButtonGroup; 36 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/components/MoreMenu.tsx: -------------------------------------------------------------------------------- 1 | import MoreHorizIcon from '@mui/icons-material/MoreHoriz'; 2 | import { ListItemIcon, ListItemText, Menu, MenuItem } from '@mui/material'; 3 | import { IconButton } from 'lightning-ui/src/design-system/components'; 4 | import React, { ReactNode } from 'react'; 5 | 6 | export type MoreMenuItem = { 7 | label: string; 8 | icon: ReactNode; 9 | onClick: () => void; 10 | disabled?: boolean; 11 | }; 12 | 13 | export type MoreMenuProps = { 14 | id: string; 15 | items: MoreMenuItem[]; 16 | }; 17 | 18 | const MoreMenu = ({ id, items }: MoreMenuProps) => { 19 | const [anchorEl, setAnchorEl] = React.useState(null); 20 | 21 | const handleClick = (event: any) => { 22 | setAnchorEl(event.currentTarget); 23 | }; 24 | 25 | const handleClose = () => { 26 | setAnchorEl(null); 27 | }; 28 | 29 | const open = Boolean(anchorEl); 30 | const menuId = open ? id : undefined; 31 | 32 | return ( 33 |
34 | 35 | 36 | 37 | 50 | {items.map(item => ( 51 | { 53 | item.onClick(); 54 | handleClose(); 55 | }} 56 | disabled={item.disabled}> 57 | {item.icon} 58 | 59 | 60 | ))} 61 | 62 |
63 | ); 64 | }; 65 | 66 | export default MoreMenu; 67 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/components/StartStopMenuItem.tsx: -------------------------------------------------------------------------------- 1 | import PlayCircleIcon from '@mui/icons-material/PlayCircle'; 2 | import StopCircleIcon from '@mui/icons-material/StopCircle'; 3 | 4 | const StartStopMenuItem = (status: string, onStart: () => void, onStop: () => void) => { 5 | if (['stopped', 'not_started'].indexOf(status) >= 0) { 6 | return { 7 | label: 'Start', 8 | icon: , 9 | onClick: onStart, 10 | }; 11 | } 12 | return { 13 | label: 'Stop', 14 | icon: , 15 | onClick: onStop, 16 | }; 17 | }; 18 | 19 | export default StartStopMenuItem; 20 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/AppClient.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | import type { BaseHttpRequest } from './core/BaseHttpRequest'; 5 | import type { OpenAPIConfig } from './core/OpenAPI'; 6 | import { AxiosHttpRequest } from './core/AxiosHttpRequest'; 7 | 8 | import { AppApiService } from './services/AppApiService'; 9 | import { AppClientCommandService } from './services/AppClientCommandService'; 10 | import { DefaultService } from './services/DefaultService'; 11 | 12 | type HttpRequestConstructor = new (config: OpenAPIConfig) => BaseHttpRequest; 13 | 14 | export class AppClient { 15 | 16 | public readonly appApi: AppApiService; 17 | public readonly appClientCommand: AppClientCommandService; 18 | public readonly default: DefaultService; 19 | 20 | public readonly request: BaseHttpRequest; 21 | 22 | constructor(config?: Partial, HttpRequest: HttpRequestConstructor = AxiosHttpRequest) { 23 | this.request = new HttpRequest({ 24 | BASE: config?.BASE ?? '', 25 | VERSION: config?.VERSION ?? '0.1.0', 26 | WITH_CREDENTIALS: config?.WITH_CREDENTIALS ?? false, 27 | CREDENTIALS: config?.CREDENTIALS ?? 'include', 28 | TOKEN: config?.TOKEN, 29 | USERNAME: config?.USERNAME, 30 | PASSWORD: config?.PASSWORD, 31 | HEADERS: config?.HEADERS, 32 | ENCODE_PATH: config?.ENCODE_PATH, 33 | }); 34 | 35 | this.appApi = new AppApiService(this.request); 36 | this.appClientCommand = new AppClientCommandService(this.request); 37 | this.default = new DefaultService(this.request); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/core/ApiError.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | import type { ApiRequestOptions } from './ApiRequestOptions'; 5 | import type { ApiResult } from './ApiResult'; 6 | 7 | export class ApiError extends Error { 8 | public readonly url: string; 9 | public readonly status: number; 10 | public readonly statusText: string; 11 | public readonly body: any; 12 | public readonly request: ApiRequestOptions; 13 | 14 | constructor(request: ApiRequestOptions, response: ApiResult, message: string) { 15 | super(message); 16 | 17 | this.name = 'ApiError'; 18 | this.url = response.url; 19 | this.status = response.status; 20 | this.statusText = response.statusText; 21 | this.body = response.body; 22 | this.request = request; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/core/ApiRequestOptions.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | export type ApiRequestOptions = { 5 | readonly method: 'GET' | 'PUT' | 'POST' | 'DELETE' | 'OPTIONS' | 'HEAD' | 'PATCH'; 6 | readonly url: string; 7 | readonly path?: Record; 8 | readonly cookies?: Record; 9 | readonly headers?: Record; 10 | readonly query?: Record; 11 | readonly formData?: Record; 12 | readonly body?: any; 13 | readonly mediaType?: string; 14 | readonly responseHeader?: string; 15 | readonly errors?: Record; 16 | }; 17 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/core/ApiResult.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | export type ApiResult = { 5 | readonly url: string; 6 | readonly ok: boolean; 7 | readonly status: number; 8 | readonly statusText: string; 9 | readonly body: any; 10 | }; 11 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/core/AxiosHttpRequest.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | import type { ApiRequestOptions } from './ApiRequestOptions'; 5 | import { BaseHttpRequest } from './BaseHttpRequest'; 6 | import type { CancelablePromise } from './CancelablePromise'; 7 | import type { OpenAPIConfig } from './OpenAPI'; 8 | import { request as __request } from './request'; 9 | 10 | export class AxiosHttpRequest extends BaseHttpRequest { 11 | 12 | constructor(config: OpenAPIConfig) { 13 | super(config); 14 | } 15 | 16 | /** 17 | * Request method 18 | * @param options The request options from the service 19 | * @returns CancelablePromise 20 | * @throws ApiError 21 | */ 22 | public override request(options: ApiRequestOptions): CancelablePromise { 23 | return __request(this.config, options); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/core/BaseHttpRequest.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | import type { ApiRequestOptions } from './ApiRequestOptions'; 5 | import type { CancelablePromise } from './CancelablePromise'; 6 | import type { OpenAPIConfig } from './OpenAPI'; 7 | 8 | export abstract class BaseHttpRequest { 9 | 10 | constructor(public readonly config: OpenAPIConfig) {} 11 | 12 | public abstract request(options: ApiRequestOptions): CancelablePromise; 13 | } 14 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/core/OpenAPI.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | import type { ApiRequestOptions } from './ApiRequestOptions'; 5 | 6 | type Resolver = (options: ApiRequestOptions) => Promise; 7 | type Headers = Record; 8 | 9 | export type OpenAPIConfig = { 10 | BASE: string; 11 | VERSION: string; 12 | WITH_CREDENTIALS: boolean; 13 | CREDENTIALS: 'include' | 'omit' | 'same-origin'; 14 | TOKEN?: string | Resolver; 15 | USERNAME?: string | Resolver; 16 | PASSWORD?: string | Resolver; 17 | HEADERS?: Headers | Resolver; 18 | ENCODE_PATH?: (path: string) => string; 19 | }; 20 | 21 | export const OpenAPI: OpenAPIConfig = { 22 | BASE: '', 23 | VERSION: '0.1.0', 24 | WITH_CREDENTIALS: false, 25 | CREDENTIALS: 'include', 26 | TOKEN: undefined, 27 | USERNAME: undefined, 28 | PASSWORD: undefined, 29 | HEADERS: undefined, 30 | ENCODE_PATH: undefined, 31 | }; 32 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/index.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | export { AppClient } from './AppClient'; 5 | 6 | export { ApiError } from './core/ApiError'; 7 | export { BaseHttpRequest } from './core/BaseHttpRequest'; 8 | export { CancelablePromise, CancelError } from './core/CancelablePromise'; 9 | export { OpenAPI } from './core/OpenAPI'; 10 | export type { OpenAPIConfig } from './core/OpenAPI'; 11 | 12 | export type { Body_upload_file_api_v1_upload_file__filename__put } from './models/Body_upload_file_api_v1_upload_file__filename__put'; 13 | export type { DataConfig } from './models/DataConfig'; 14 | export type { DeleteDataConfig } from './models/DeleteDataConfig'; 15 | export type { DeleteExperimentConfig } from './models/DeleteExperimentConfig'; 16 | export type { DeleteSweepConfig } from './models/DeleteSweepConfig'; 17 | export type { Distributions } from './models/Distributions'; 18 | export type { DownloadArtifactsConfig } from './models/DownloadArtifactsConfig'; 19 | export type { ExperimentConfig } from './models/ExperimentConfig'; 20 | export type { HTTPValidationError } from './models/HTTPValidationError'; 21 | export type { ShowArtifactsConfig } from './models/ShowArtifactsConfig'; 22 | export type { StopExperimentConfig } from './models/StopExperimentConfig'; 23 | export type { StopSweepConfig } from './models/StopSweepConfig'; 24 | export type { StopTensorboardConfig } from './models/StopTensorboardConfig'; 25 | export type { SweepConfig } from './models/SweepConfig'; 26 | export type { TensorboardConfig } from './models/TensorboardConfig'; 27 | export type { ValidationError } from './models/ValidationError'; 28 | 29 | export { AppApiService } from './services/AppApiService'; 30 | export { AppClientCommandService } from './services/AppClientCommandService'; 31 | export { DefaultService } from './services/DefaultService'; 32 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/models/Body_upload_file_api_v1_upload_file__filename__put.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | 5 | export type Body_upload_file_api_v1_upload_file__filename__put = { 6 | uploaded_file: Blob; 7 | }; 8 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/models/DataConfig.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | 5 | export type DataConfig = { 6 | name: string; 7 | source: string; 8 | mount_path: string; 9 | }; 10 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/models/DeleteDataConfig.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | 5 | export type DeleteDataConfig = { 6 | name: string; 7 | }; 8 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/models/DeleteExperimentConfig.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | 5 | export type DeleteExperimentConfig = { 6 | name: string; 7 | }; 8 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/models/DeleteSweepConfig.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | 5 | export type DeleteSweepConfig = { 6 | name: string; 7 | }; 8 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/models/Distributions.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | 5 | export type Distributions = { 6 | distribution: string; 7 | params: Record | Array)>; 8 | }; 9 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/models/DownloadArtifactsConfig.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | 5 | export type DownloadArtifactsConfig = { 6 | include?: string; 7 | exclude?: string; 8 | }; 9 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/models/ExperimentConfig.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | 5 | export type ExperimentConfig = { 6 | name: string; 7 | best_model_score?: number; 8 | monitor?: string; 9 | best_model_path?: string; 10 | last_model_path?: string; 11 | stage?: string; 12 | params: Record | Array)>; 13 | exception?: string; 14 | progress?: number; 15 | total_parameters?: string; 16 | start_time?: string; 17 | end_time?: string; 18 | }; 19 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/models/HTTPValidationError.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | 5 | import type { ValidationError } from './ValidationError'; 6 | 7 | export type HTTPValidationError = { 8 | detail?: Array; 9 | }; 10 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/models/ShowArtifactsConfig.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | 5 | export type ShowArtifactsConfig = { 6 | include?: string; 7 | exclude?: string; 8 | }; 9 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/models/StopExperimentConfig.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | 5 | export type StopExperimentConfig = { 6 | name: string; 7 | }; 8 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/models/StopSweepConfig.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | 5 | export type StopSweepConfig = { 6 | sweep_id: string; 7 | }; 8 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/models/StopTensorboardConfig.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | 5 | export type StopTensorboardConfig = { 6 | sweep_id: string; 7 | }; 8 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/models/SweepConfig.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | 5 | import type { Distributions } from './Distributions'; 6 | import type { ExperimentConfig } from './ExperimentConfig'; 7 | 8 | export type SweepConfig = { 9 | sweep_id: string; 10 | script_path: string; 11 | total_experiments: number; 12 | parallel_experiments: number; 13 | total_experiments_done?: number; 14 | requirements: Array; 15 | packages: Array; 16 | script_args: Array; 17 | algorithm: string; 18 | distributions: Record; 19 | logger_url?: string; 20 | experiments: Record; 21 | framework: string; 22 | cloud_compute?: string; 23 | num_nodes?: number; 24 | artifacts_path?: string; 25 | logger: string; 26 | direction: string; 27 | stage?: string; 28 | desired_stage?: string; 29 | shm_size?: number; 30 | disk_size?: number; 31 | pip_install_source?: boolean; 32 | data: Record; 33 | username?: string; 34 | }; 35 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/models/TensorboardConfig.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | 5 | export type TensorboardConfig = { 6 | sweep_id: string; 7 | shared_folder: string; 8 | stage?: string; 9 | desired_stage?: string; 10 | url?: string; 11 | }; 12 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/models/ValidationError.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | 5 | export type ValidationError = { 6 | loc: Array<(string | number)>; 7 | msg: string; 8 | type: string; 9 | }; 10 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/generated/services/AppApiService.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | import type { StopTensorboardConfig } from '../models/StopTensorboardConfig'; 5 | import type { TensorboardConfig } from '../models/TensorboardConfig'; 6 | 7 | import type { CancelablePromise } from '../core/CancelablePromise'; 8 | import type { BaseHttpRequest } from '../core/BaseHttpRequest'; 9 | 10 | export class AppApiService { 11 | 12 | constructor(public readonly httpRequest: BaseHttpRequest) {} 13 | 14 | /** 15 | * Run Tensorboard 16 | * @param requestBody 17 | * @returns any Successful Response 18 | * @throws ApiError 19 | */ 20 | public runTensorboardApiRunTensorboardPost( 21 | requestBody: TensorboardConfig, 22 | ): CancelablePromise { 23 | return this.httpRequest.request({ 24 | method: 'POST', 25 | url: '/api/run/tensorboard', 26 | body: requestBody, 27 | mediaType: 'application/json', 28 | errors: { 29 | 422: `Validation Error`, 30 | }, 31 | }); 32 | } 33 | 34 | /** 35 | * Stop Tensorboard 36 | * @param requestBody 37 | * @returns any Successful Response 38 | * @throws ApiError 39 | */ 40 | public stopTensorboardApiStopTensorboardPost( 41 | requestBody: StopTensorboardConfig, 42 | ): CancelablePromise { 43 | return this.httpRequest.request({ 44 | method: 'POST', 45 | url: '/api/stop/tensorboard', 46 | body: requestBody, 47 | mediaType: 'application/json', 48 | errors: { 49 | 422: `Validation Error`, 50 | }, 51 | }); 52 | } 53 | 54 | /** 55 | * Show Tensorboards 56 | * @returns any Successful Response 57 | * @throws ApiError 58 | */ 59 | public showTensorboardsApiShowTensorboardsPost(): CancelablePromise { 60 | return this.httpRequest.request({ 61 | method: 'POST', 62 | url: '/api/show/tensorboards', 63 | }); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/hooks/useClientDataState.tsx: -------------------------------------------------------------------------------- 1 | import { useSnackbar } from 'lightning-ui/src/design-system/components'; 2 | import React, { useEffect } from 'react'; 3 | import { AppClient } from '../generated'; 4 | import { getUrl } from '../utilities'; 5 | 6 | export const appClient = new AppClient({ 7 | BASE: getUrl(), 8 | }); 9 | 10 | const clientEndpoints = { 11 | sweeps: (appClient: AppClient) => appClient.appClientCommand.showSweepsCommandShowSweepsPost(), 12 | tensorboards: (appClient: AppClient) => appClient.appApi.showTensorboardsApiShowTensorboardsPost(), 13 | data: (appClient: AppClient) => appClient.appClientCommand.showDatasetsCommandShowDatasetsPost(), 14 | }; 15 | 16 | const clientDataContexts = { 17 | sweeps: React.createContext([]), 18 | tensorboards: React.createContext([]), 19 | data: React.createContext([]), 20 | }; 21 | 22 | export const ClientDataProvider = (props: { endpoint: keyof typeof clientEndpoints; children: React.ReactNode }) => { 23 | const [isErrorState, setIsErrorState] = React.useState(false); 24 | const [state, dispatch] = React.useReducer((state: any[], newValue: any[]) => newValue, []); 25 | const { enqueueSnackbar } = useSnackbar(); 26 | 27 | useEffect(() => { 28 | const post = () => { 29 | clientEndpoints[props.endpoint](appClient) 30 | .then(data => { 31 | if (isErrorState) { 32 | setIsErrorState(false); 33 | } 34 | dispatch(data); 35 | }) 36 | .catch(error => { 37 | if (!isErrorState) { 38 | setIsErrorState(true); 39 | enqueueSnackbar({ 40 | title: 'Error Fetching Data', 41 | children: 'Try reloading the page', 42 | severity: 'error', 43 | }); 44 | } 45 | }); 46 | }; 47 | 48 | post(); 49 | 50 | const interval = setInterval(() => { 51 | post(); 52 | }, 1000); 53 | 54 | return () => clearInterval(interval); 55 | }, [isErrorState]); 56 | 57 | const context = clientDataContexts[props.endpoint]; 58 | return {props.children}; 59 | }; 60 | 61 | const useClientDataState = (endpoint: keyof typeof clientEndpoints) => { 62 | const clientData = React.useContext(clientDataContexts[endpoint]); 63 | 64 | return clientData; 65 | }; 66 | 67 | export default useClientDataState; 68 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/hooks/useSelectedTabState.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const defaultSelectedTab = 0; 4 | const selectedTabContext = React.createContext(defaultSelectedTab); 5 | const dispatchContext = React.createContext((newValue: number): void => {}); 6 | 7 | // @ts-ignore 8 | export const SelectedTabProvider = ({ children }) => { 9 | const [state, dispatch] = React.useReducer((state: number, newValue: number) => newValue, defaultSelectedTab); 10 | return ( 11 | 12 | void}>{children} 13 | 14 | ); 15 | }; 16 | 17 | const useSelectedTabState = () => { 18 | const selectedTab = React.useContext(selectedTabContext); 19 | const setSelectedTab = React.useContext(dispatchContext); 20 | 21 | return { 22 | selectedTab, 23 | setSelectedTab, 24 | }; 25 | }; 26 | 27 | export default useSelectedTabState; 28 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/hooks/useShowHelpPageState.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export enum HelpPageState { 4 | forced = 'forced', 5 | shown = 'shown', 6 | notShown = 'not shown', 7 | } 8 | 9 | const defaultShowHelpPage = HelpPageState.notShown; 10 | const showHelpPageContext = React.createContext(defaultShowHelpPage); 11 | const dispatchContext = React.createContext((newValue: HelpPageState): void => {}); 12 | 13 | // @ts-ignore 14 | export const ShowHelpPageProvider = ({ children }) => { 15 | const [state, dispatch] = React.useReducer( 16 | (state: HelpPageState, newValue: HelpPageState) => newValue, 17 | defaultShowHelpPage, 18 | ); 19 | return ( 20 | 21 | void}> 22 | {children} 23 | 24 | 25 | ); 26 | }; 27 | 28 | const useShowHelpPageState = () => { 29 | const showHelpPage = React.useContext(showHelpPageContext); 30 | const setShowHelpPage = React.useContext(dispatchContext); 31 | 32 | return { 33 | showHelpPage, 34 | setShowHelpPage, 35 | }; 36 | }; 37 | 38 | export default useShowHelpPageState; 39 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; 4 | -webkit-font-smoothing: antialiased; 5 | -moz-osx-font-smoothing: grayscale; 6 | overflow-y: overlay; 7 | } 8 | 9 | code { 10 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; 11 | } 12 | 13 | pre { 14 | overflow: scroll; 15 | font-size: 0.8em; 16 | max-height: 40em; 17 | } 18 | 19 | @import 'lightning-ui/src/design-system/style.css'; 20 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/index.tsx: -------------------------------------------------------------------------------- 1 | import FontFaceObserver from 'fontfaceobserver'; 2 | import React from 'react'; 3 | import ReactDOM from 'react-dom'; 4 | import App from './App'; 5 | import './index.css'; 6 | import reportWebVitals from './reportWebVitals'; 7 | 8 | // Make sure Roboto Mono is loaded before rendering the app as it is used within a canvas element 9 | // The rest of the fonts don't need to be loaded before the render as they will be applied 10 | // as soon as they are available 11 | const font = new FontFaceObserver('Roboto Mono'); 12 | font.load().then(() => { 13 | ReactDOM.render( 14 | 15 | 16 | , 17 | document.getElementById('root'), 18 | ); 19 | }); 20 | 21 | // If you want to start measuring performance in your app, pass a function 22 | // to log results (for example: reportWebVitals(console.log)) 23 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 24 | reportWebVitals(); 25 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/reportWebVitals.ts: -------------------------------------------------------------------------------- 1 | import { ReportHandler } from 'web-vitals'; 2 | 3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => { 4 | if (onPerfEntry && onPerfEntry instanceof Function) { 5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 6 | getCLS(onPerfEntry); 7 | getFID(onPerfEntry); 8 | getFCP(onPerfEntry); 9 | getLCP(onPerfEntry); 10 | getTTFB(onPerfEntry); 11 | }); 12 | } 13 | }; 14 | 15 | export default reportWebVitals; 16 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/svg.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.svg' { 2 | import * as React from 'react'; 3 | 4 | export const ReactComponent: React.FunctionComponent & { title?: string }>; 5 | 6 | const src: string; 7 | export default src; 8 | } 9 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/types/lightning.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Represents the internal state of a Lightning app as exposed by 3 | * the `/state` endpoint of the Lightning HTTP API. 4 | */ 5 | export type LightingState = { 6 | vars: { 7 | _layout: Layout | Layout[]; 8 | [key: string]: any; 9 | }; 10 | calls: { 11 | [key: string]: { 12 | name: string; 13 | call_hash: string; 14 | ret: boolean; 15 | }; 16 | }; 17 | flows: { 18 | [key: string]: ChildState; 19 | }; 20 | works: { 21 | [key: string]: any; 22 | }; 23 | changes: { 24 | [key: string]: any; 25 | }; 26 | app_state: { 27 | stage: AppStage; 28 | }; 29 | }; 30 | 31 | export type ChildState = Omit; 32 | 33 | export type Layout = LayoutBranch | LayoutLeaf; 34 | 35 | export type LayoutBranch = { 36 | name: string; 37 | content: string; 38 | }; 39 | 40 | export type LayoutLeaf = { 41 | name: string; 42 | type: LayoutType; 43 | source?: string; 44 | target: string; 45 | }; 46 | 47 | export enum LayoutType { 48 | web = 'web', 49 | streamlit = 'streamlit', 50 | } 51 | 52 | export enum AppStage { 53 | blocking = 'blocking', 54 | restarting = 'restarting', 55 | running = 'running', 56 | stopping = 'stopping', 57 | } 58 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/src/utilities.ts: -------------------------------------------------------------------------------- 1 | export function getUrl() { 2 | let url = window.location != window.parent.location ? document.referrer : document.location.href; 3 | url = url.replace(/\/$/, '').replace('/view/undefined', ''); 4 | return url; 5 | } 6 | 7 | export function getAppId() { 8 | let app_id = getUrl() 9 | .replace(/(^\w+:|^)\/\//, '') 10 | .split('.')[0]; 11 | app_id = app_id === '127' ? 'localhost' : app_id; 12 | return app_id; 13 | } 14 | 15 | function zeroPad(num: number, places: number) { 16 | const zero = places - num.toString().length + 1; 17 | return Array(+(zero > 0 && zero)).join('0') + num; 18 | } 19 | 20 | export function formatDurationFrom(start_time: number) { 21 | return formatDurationStartEnd(new Date().getTime() / 1000, start_time); 22 | } 23 | 24 | export function formatDurationStartEnd(end_time: number, start_time: number) { 25 | let duration = end_time - start_time; 26 | const hours = Math.floor(duration / 1440); 27 | duration = duration - hours * 1440; 28 | const minutes = Math.floor(duration / 60); 29 | duration = duration - minutes * 60; 30 | const seconds = Math.floor(duration); 31 | return `${zeroPad(hours, 2)}:${zeroPad(minutes, 2)}:${zeroPad(seconds, 2)}`; 32 | } 33 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "baseUrl": "src/", 7 | "skipLibCheck": true, 8 | "esModuleInterop": true, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "module": "esnext", 14 | "moduleResolution": "node", 15 | "resolveJsonModule": true, 16 | "isolatedModules": true, 17 | "noEmit": true, 18 | "jsx": "react-jsx" 19 | }, 20 | "types": ["node"], 21 | "include": ["src"] 22 | } 23 | -------------------------------------------------------------------------------- /lightning_training_studio/app/ui/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "esnext", 5 | "moduleResolution": "node" 6 | }, 7 | "include": ["vite.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /lightning_training_studio/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/lightning_training_studio/commands/__init__.py -------------------------------------------------------------------------------- /lightning_training_studio/commands/artifacts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/lightning_training_studio/commands/artifacts/__init__.py -------------------------------------------------------------------------------- /lightning_training_studio/commands/data/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/lightning_training_studio/commands/data/__init__.py -------------------------------------------------------------------------------- /lightning_training_studio/commands/data/create.py: -------------------------------------------------------------------------------- 1 | import os 2 | from argparse import ArgumentParser 3 | 4 | from lightning.app.utilities.commands import ClientCommand 5 | from pydantic import validator 6 | from sqlmodel import Field, SQLModel 7 | 8 | 9 | class DataConfig(SQLModel, table=True): 10 | __table_args__ = {"extend_existing": True} 11 | 12 | name: str = Field(primary_key=True) 13 | source: str 14 | mount_path: str 15 | 16 | @validator("source") 17 | def source_validator(cls, v): 18 | if not v.startswith("s3://"): 19 | raise Exception('The `source` needs to start with "s3://"') 20 | elif not v.endswith("/"): 21 | raise Exception("The `source` needs to end with in a trailing slash (`/`)") 22 | return v 23 | 24 | @validator("mount_path") 25 | def mount_path_validator(cls, v, values, **kwargs): 26 | if not v.startswith("/"): 27 | raise Exception("The `mount_path` needs to start with a leading slash (`/`)") 28 | elif not v.endswith("/"): 29 | raise Exception("The `mount_path` needs to end with in a trailing slash (`/`)") 30 | return v 31 | 32 | 33 | class AddDatasetCommand(ClientCommand): 34 | description = """ 35 | To create a dataset association, provide a public S3 bucket and an optional mount point. 36 | The contents of the bucket can then be accessed through the file system in experiments and sweeps. 37 | """ 38 | 39 | def run(self) -> None: 40 | parser = ArgumentParser() 41 | 42 | parser.add_argument("--name", type=str, required=True, help="The name of the Data.") 43 | parser.add_argument("--source", type=str, required=True, help="The S3 URL of the Data.") 44 | parser.add_argument( 45 | "--mount_path", 46 | type=str, 47 | default=None, 48 | help="Where the Data should be mounted in experiments and sweeps. Defaults to `/data//`.", 49 | ) 50 | 51 | hparams = parser.parse_args() 52 | mount_path = hparams.mount_path if hparams.mount_path else os.path.join("/data", hparams.name, "") 53 | response = self.invoke_handler( 54 | config=DataConfig(name=hparams.name, source=hparams.source, mount_path=mount_path) 55 | ) 56 | print(response) 57 | -------------------------------------------------------------------------------- /lightning_training_studio/commands/data/delete.py: -------------------------------------------------------------------------------- 1 | from argparse import ArgumentParser 2 | 3 | from lightning.app.utilities.commands import ClientCommand 4 | from sqlmodel import SQLModel 5 | 6 | 7 | class DeleteDataConfig(SQLModel): 8 | name: str 9 | 10 | 11 | class RemoveDatasetCommand(ClientCommand): 12 | description = """To delete a dataset association, note this doesn't delete the data, but only the reference.""" 13 | 14 | def run(self) -> None: 15 | parser = ArgumentParser() 16 | 17 | parser.add_argument("--name", type=str, required=True, help="The name of the Data.") 18 | 19 | hparams = parser.parse_args() 20 | response = self.invoke_handler(config=DeleteDataConfig(name=hparams.name)) 21 | print(response) 22 | -------------------------------------------------------------------------------- /lightning_training_studio/commands/data/show.py: -------------------------------------------------------------------------------- 1 | from lightning.app.utilities.commands import ClientCommand 2 | from rich.console import Console 3 | from rich.table import Table 4 | 5 | 6 | class ShowDatasetsCommand(ClientCommand): 7 | description = "To list all dataset associations." 8 | 9 | def run(self) -> None: 10 | response = self.invoke_handler() 11 | 12 | table = Table( 13 | "name", 14 | "source", 15 | "mount_path", 16 | title="Data", 17 | show_header=True, 18 | header_style="bold green", 19 | ) 20 | 21 | for mount in response: 22 | table.add_row( 23 | mount["name"], 24 | mount["source"], 25 | mount["mount_path"], 26 | ) 27 | console = Console() 28 | console.print(table) 29 | -------------------------------------------------------------------------------- /lightning_training_studio/commands/experiment/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/lightning_training_studio/commands/experiment/__init__.py -------------------------------------------------------------------------------- /lightning_training_studio/commands/experiment/delete.py: -------------------------------------------------------------------------------- 1 | from argparse import ArgumentParser 2 | 3 | from lightning.app.utilities.commands import ClientCommand 4 | from pydantic import BaseModel 5 | 6 | 7 | class DeleteExperimentConfig(BaseModel): 8 | name: str 9 | 10 | 11 | class DeleteExperimentCommand(ClientCommand): 12 | description = """To delete an experiment. The artifacts are still available after the operation is complete.""" 13 | 14 | def run(self) -> None: 15 | parser = ArgumentParser() 16 | parser.add_argument("--name", type=str, required=True, help="The associated experiment `name` to delete.") 17 | hparams = parser.parse_args() 18 | response = self.invoke_handler(config=DeleteExperimentConfig(name=hparams.name)) 19 | print(response) 20 | -------------------------------------------------------------------------------- /lightning_training_studio/commands/experiment/show.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from typing import List 3 | 4 | from lightning.app.utilities.commands import ClientCommand 5 | from rich.console import Console 6 | from rich.table import Table 7 | 8 | from lightning_training_studio.commands.sweep.run import SweepConfig 9 | 10 | 11 | def _show_experiments(sweeps: List[SweepConfig]): 12 | table = Table( 13 | "name", 14 | "cloud compute", 15 | "progress", 16 | "best model score", 17 | "sweep name", 18 | title="Experiments", 19 | show_header=True, 20 | header_style="bold green", 21 | ) 22 | 23 | for sweep in sweeps: 24 | experiments = sweep.experiments.values() 25 | for experiment in experiments: 26 | table.add_row( 27 | str(experiment.name), 28 | sweep.cloud_compute, 29 | str(experiment.progress) if experiment.stage != "failed" else "failed", 30 | str(round(experiment.best_model_score, 2) if experiment.best_model_score else None), 31 | None if len(experiments) == 1 else sweep.sweep_id, 32 | ) 33 | console = Console() 34 | console.print(table) 35 | 36 | 37 | class ShowExperimentsCommand(ClientCommand): 38 | description = "To show experiments and their statuses." 39 | 40 | def run(self) -> None: 41 | if sys.argv and sys.argv[-1] == "--help": 42 | print("optional arguments:") 43 | print(" -h, --help show this help message and exit") 44 | return 45 | 46 | # 1: Collect the SweepConfig 47 | resp = self.invoke_handler() 48 | 49 | # 3: Display the Sweeps or Sweep 50 | # TODO: Undestand why the format isn't the same 51 | try: 52 | sweeps = [SweepConfig.parse_raw(sweep) for sweep in resp] 53 | except Exception: 54 | sweeps = [SweepConfig(**sweep) for sweep in resp] 55 | 56 | _show_experiments(sweeps) 57 | -------------------------------------------------------------------------------- /lightning_training_studio/commands/experiment/stop.py: -------------------------------------------------------------------------------- 1 | from argparse import ArgumentParser 2 | 3 | from lightning.app.utilities.commands import ClientCommand 4 | from pydantic import BaseModel 5 | 6 | 7 | class StopExperimentConfig(BaseModel): 8 | name: str 9 | 10 | 11 | class StopExperimentCommand(ClientCommand): 12 | description = "To stop an experiment, note that currently experiments cannot be resumed." 13 | 14 | def run(self) -> None: 15 | parser = ArgumentParser() 16 | parser.add_argument("--name", type=str, required=True, help="The associated `experiment_name` to stop.") 17 | hparams = parser.parse_args() 18 | response = self.invoke_handler(config=StopExperimentConfig(name=hparams.name)) 19 | print(response) 20 | -------------------------------------------------------------------------------- /lightning_training_studio/commands/logs/show.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import sys 3 | from typing import List 4 | 5 | from lightning.app.cli.commands.connection import _retrieve_connection_to_an_app 6 | from lightning.app.cli.commands.logs import _show_logs 7 | from lightning.app.utilities.commands import ClientCommand 8 | from pydantic import BaseModel 9 | 10 | 11 | class ShowLogsConfig(BaseModel): 12 | name: str 13 | components: List[str] 14 | 15 | 16 | class ShowLogsCommand(ClientCommand): 17 | description: str = "To show the logs of an experiment or sweep, use the option to follow the logs as they stream." 18 | 19 | def run(self): 20 | parser = argparse.ArgumentParser() 21 | parser.add_argument( 22 | "--names", 23 | nargs="+", 24 | default=[], 25 | help="The name or names of the Experiment(s), Sweep(s) or components to show logs from.", 26 | ) 27 | parser.add_argument("-f", "--follow", action="store_true", default=False) 28 | hparams = parser.parse_args() 29 | 30 | logs_config: List[ShowLogsConfig] = self.invoke_handler() 31 | 32 | components = [] 33 | sweeps = [c["name"] for c in logs_config if len(c["components"]) > 1] 34 | experiments = [c["name"] for c in logs_config if len(c["components"]) == 1] 35 | 36 | if not hparams.names: 37 | for config in logs_config: 38 | components.extend(config["components"]) 39 | else: 40 | for config in logs_config: 41 | for name in hparams.names: 42 | if name == config["name"]: 43 | components.extend(config["components"]) 44 | 45 | if not components: 46 | if not sweeps and not experiments: 47 | print("There isn't logs yet as you haven't run any experiments or sweeps.") 48 | else: 49 | print( 50 | f"The provided name {hparams.names} wasn't found." 51 | f" Here are the sweeps {sweeps} and experiments {experiments}." 52 | ) 53 | sys.exit(0) 54 | 55 | app_name, _ = _retrieve_connection_to_an_app() 56 | 57 | if app_name == "localhost": 58 | print("The command `show logs` is currently supported only in the cloud.") 59 | sys.exit(0) 60 | 61 | _show_logs(app_name, list(set(components)), hparams.follow) 62 | -------------------------------------------------------------------------------- /lightning_training_studio/commands/notebook/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/lightning_training_studio/commands/notebook/__init__.py -------------------------------------------------------------------------------- /lightning_training_studio/commands/notebook/run.py: -------------------------------------------------------------------------------- 1 | import os 2 | from argparse import ArgumentParser 3 | from getpass import getuser 4 | from typing import List 5 | from uuid import uuid4 6 | 7 | from lightning.app.utilities.commands import ClientCommand 8 | from sqlalchemy import Column 9 | from sqlmodel import Field, SQLModel 10 | 11 | from lightning_training_studio.utilities.enum import Stage 12 | from lightning_training_studio.utilities.utils import pydantic_column_type 13 | 14 | 15 | class NotebookConfig(SQLModel, table=True): 16 | __table_args__ = {"extend_existing": True} 17 | 18 | notebook_name: str = Field(primary_key=True) 19 | requirements: List[str] = Field(..., sa_column=Column(pydantic_column_type(List[str]))) 20 | cloud_compute: str 21 | stage: str = Stage.NOT_STARTED 22 | desired_stage: str = Stage.RUNNING 23 | url: str = "" 24 | start_time: float = -1 25 | 26 | 27 | class RunNotebookCommand(ClientCommand): 28 | def run(self) -> None: 29 | parser = ArgumentParser() 30 | 31 | parser.add_argument("--name", default=None, help="The name of your notebook to run.") 32 | parser.add_argument( 33 | "--requirements", 34 | default=[], 35 | type=lambda s: [v.replace(" ", "") for v in s.split(",")] if "," in s else s, 36 | help="List of requirements separated by a comma or requirements.txt filepath.", 37 | ) 38 | parser.add_argument( 39 | "--cloud_compute", 40 | default="cpu", 41 | choices=["cpu", "cpu-small", "cpu-medium", "gpu", "gpu-fast", "gpu-fast-multi"], 42 | type=str, 43 | help="The machine to use in the cloud.", 44 | ) 45 | 46 | hparams, _ = parser.parse_known_args() 47 | 48 | if isinstance(hparams.requirements, str) and os.path.exists(hparams.requirements): 49 | with open(hparams.requirements) as f: 50 | hparams.requirements = [line.replace("\n", "") for line in f.readlines()] 51 | 52 | id = str(uuid4()).split("-")[0] 53 | notebook_name = hparams.name or f"{getuser()}-{id}" 54 | 55 | config = NotebookConfig( 56 | notebook_name=notebook_name, 57 | requirements=hparams.requirements, 58 | cloud_compute=hparams.cloud_compute, 59 | ) 60 | response = self.invoke_handler(config=config) 61 | print(response) 62 | -------------------------------------------------------------------------------- /lightning_training_studio/commands/notebook/show.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | from lightning.app.utilities.commands import ClientCommand 4 | from rich.console import Console 5 | from rich.table import Table 6 | 7 | from lightning_training_studio.commands.notebook.run import NotebookConfig 8 | 9 | 10 | def _show_notebooks(notebooks: List[NotebookConfig]): 11 | table = Table( 12 | "name", 13 | "status", 14 | "cloud_compute", 15 | "requirements", 16 | title="Notebooks", 17 | show_header=True, 18 | header_style="bold green", 19 | ) 20 | 21 | for notebook in notebooks: 22 | table.add_row( 23 | notebook.notebook_name, 24 | notebook.stage, 25 | notebook.cloud_compute, 26 | str(notebook.requirements), 27 | ) 28 | console = Console() 29 | console.print(table) 30 | 31 | 32 | class ShowNotebookCommand(ClientCommand): 33 | def run(self) -> None: 34 | response = self.invoke_handler() 35 | _show_notebooks([NotebookConfig(**notebook) for notebook in response]) 36 | -------------------------------------------------------------------------------- /lightning_training_studio/commands/notebook/stop.py: -------------------------------------------------------------------------------- 1 | from argparse import ArgumentParser 2 | 3 | from lightning.app.utilities.commands import ClientCommand 4 | from pydantic import BaseModel 5 | 6 | 7 | class StopNotebookConfig(BaseModel): 8 | notebook_name: str 9 | 10 | 11 | class StopNotebookCommand(ClientCommand): 12 | def run(self) -> None: 13 | parser = ArgumentParser() 14 | parser.add_argument("--name", required=True, help="The name of your notebook to be stopped.") 15 | hparams, _ = parser.parse_known_args() 16 | response = self.invoke_handler(config=StopNotebookConfig(notebook_name=hparams.name)) 17 | print(response) 18 | -------------------------------------------------------------------------------- /lightning_training_studio/commands/sweep/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/lightning_training_studio/commands/sweep/__init__.py -------------------------------------------------------------------------------- /lightning_training_studio/commands/sweep/delete.py: -------------------------------------------------------------------------------- 1 | from argparse import ArgumentParser 2 | 3 | from lightning.app.utilities.commands import ClientCommand 4 | from pydantic import BaseModel 5 | 6 | 7 | class DeleteSweepConfig(BaseModel): 8 | name: str 9 | 10 | 11 | class DeleteSweepCommand(ClientCommand): 12 | description = "To delete a sweep, note that the artifacts will still be available after the operation is complete." 13 | 14 | def run(self) -> None: 15 | parser = ArgumentParser() 16 | parser.add_argument("--name", type=str, required=True, help="The associated `sweep_id` to delete.") 17 | hparams = parser.parse_args() 18 | response = self.invoke_handler(config=DeleteSweepConfig(name=hparams.name)) 19 | print(response) 20 | -------------------------------------------------------------------------------- /lightning_training_studio/commands/sweep/show.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | from typing import Any, Dict, List, Optional 3 | 4 | import requests 5 | from lightning.app.utilities.commands import ClientCommand 6 | from pydantic import BaseModel 7 | from rich.console import Console 8 | from rich.table import Table 9 | 10 | from lightning_training_studio.commands.sweep.run import SweepConfig 11 | 12 | 13 | def _show_sweeps(sweeps: List[SweepConfig]): 14 | table = Table( 15 | "name", 16 | "cloud compute", 17 | "total experiments", 18 | "total experiments done", 19 | title="Sweep", 20 | show_header=True, 21 | header_style="bold green", 22 | ) 23 | 24 | for sweep in sweeps: 25 | table.add_row( 26 | sweep.sweep_id, 27 | sweep.cloud_compute, 28 | str(sweep.total_experiments), 29 | str(sweep.total_experiments_done), 30 | ) 31 | 32 | console = Console() 33 | console.print(table) 34 | 35 | 36 | class ShowSweepsCommand(ClientCommand): 37 | description = "To show all sweeps and their statuses, or the experiments for a given sweep." 38 | 39 | # TODO: (tchaton) Upstream to Lightning 40 | def invoke_handler(self, config: Optional[BaseModel] = None) -> Dict[str, Any]: 41 | command = self.command_name.replace(" ", "_") 42 | resp = requests.post(self.app_url + f"/command/{command}", data=config.json() if config else None) 43 | assert resp.status_code == 200, resp.json() 44 | return resp.json() 45 | 46 | def run(self) -> None: 47 | # 1. Parse the user arguments. 48 | parser = argparse.ArgumentParser() 49 | parser.add_argument("--name", type=str, default=None, help="Provide the `name` to be showed.") 50 | hparams = parser.parse_args() 51 | 52 | # 2: Collect the SweepConfig 53 | resp = self.invoke_handler() 54 | 55 | # 3: Display the Sweeps or Sweep 56 | # TODO: Undestand why the format isn't the same 57 | try: 58 | sweeps = [SweepConfig.parse_raw(sweep) for sweep in resp] 59 | except Exception: 60 | sweeps = [SweepConfig(**sweep) for sweep in resp] 61 | 62 | if hparams.name is None: 63 | _show_sweeps(sweeps) 64 | else: 65 | matching_sweep = [sweep for sweep in sweeps if sweep.sweep_id == hparams.name] 66 | if not matching_sweep: 67 | raise Exception( 68 | "The provided `sweep_id` doesn't exists. " 69 | f"Here are the available ones {[s.sweep_id for s in sweeps]}" 70 | ) 71 | assert len(matching_sweep) == 1 72 | _show_sweeps(matching_sweep) 73 | -------------------------------------------------------------------------------- /lightning_training_studio/commands/sweep/stop.py: -------------------------------------------------------------------------------- 1 | from argparse import ArgumentParser 2 | 3 | from lightning.app.utilities.commands import ClientCommand 4 | from pydantic import BaseModel 5 | 6 | 7 | class StopSweepConfig(BaseModel): 8 | sweep_id: str 9 | 10 | 11 | class StopSweepCommand(ClientCommand): 12 | description = "To stop all experiments in a sweep, note that currently sweeps cannot be resumed." 13 | 14 | def run(self) -> None: 15 | parser = ArgumentParser() 16 | parser.add_argument("--name", type=str, help="The associated `sweep_id` to stop.") 17 | hparams = parser.parse_args() 18 | response = self.invoke_handler(config=StopSweepConfig(sweep_id=hparams.name)) 19 | print(response) 20 | -------------------------------------------------------------------------------- /lightning_training_studio/commands/tensorboard/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/lightning_training_studio/commands/tensorboard/__init__.py -------------------------------------------------------------------------------- /lightning_training_studio/commands/tensorboard/stop.py: -------------------------------------------------------------------------------- 1 | from sqlmodel import Field, SQLModel 2 | 3 | from lightning_training_studio.utilities.enum import Stage 4 | 5 | 6 | class TensorboardConfig(SQLModel, table=True): 7 | sweep_id: str = Field(primary_key=True) 8 | shared_folder: str 9 | stage: str = Stage.NOT_STARTED 10 | desired_stage: str = Stage.RUNNING 11 | url: str = "" 12 | 13 | 14 | class StopTensorboardConfig(SQLModel): 15 | sweep_id: str 16 | -------------------------------------------------------------------------------- /lightning_training_studio/components/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/lightning_training_studio/components/__init__.py -------------------------------------------------------------------------------- /lightning_training_studio/components/notebook.py: -------------------------------------------------------------------------------- 1 | import time 2 | from subprocess import Popen 3 | from typing import Optional 4 | 5 | from lightning_utilities.core.imports import package_available 6 | 7 | if package_available("lai_jupyter"): 8 | from lai_jupyter import JupyterLab 9 | else: 10 | 11 | class JupyterLab: 12 | pass 13 | 14 | 15 | from lightning import CloudCompute 16 | 17 | from lightning_training_studio.commands.notebook.run import NotebookConfig 18 | from lightning_training_studio.controllers.controller import ControllerResource 19 | from lightning_training_studio.utilities.enum import Stage 20 | 21 | 22 | class JupyterLab(JupyterLab, ControllerResource): 23 | model = NotebookConfig 24 | 25 | def __init__(self, config: NotebookConfig, **kwargs): 26 | super().__init__(cloud_compute=CloudCompute(name=config.cloud_compute), **kwargs) 27 | self._process: Optional[Popen] = None 28 | 29 | reqs = self.cloud_build_config.requirements 30 | self.cloud_build_config.requirements = (reqs if reqs else []) + config.requirements 31 | 32 | self.notebook_name = config.notebook_name 33 | self.requirements = config.requirements 34 | self.desired_stage = config.desired_stage 35 | self.stage = config.stage 36 | self.start_time = config.start_time 37 | 38 | def run(self, *args, **kwargs): 39 | super().run() 40 | self.stage = Stage.RUNNING 41 | self.start_time = time.time() 42 | 43 | def on_exit(self): 44 | assert self._process 45 | self._process.kill() 46 | 47 | def on_collect_model(self, model_dict): 48 | model_dict["cloud_compute"] = self.cloud_compute.name 49 | if self.stage == Stage.RUNNING and self.url: 50 | model_dict["url"] = self.url 51 | else: 52 | model_dict.pop("url", None) 53 | -------------------------------------------------------------------------------- /lightning_training_studio/components/tensorboard.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pathlib import Path 3 | from subprocess import Popen 4 | from uuid import uuid4 5 | 6 | from lightning import LightningWork 7 | from lightning.app.storage import Drive 8 | from lightning.app.storage.path import _filesystem 9 | 10 | from lightning_training_studio.commands.tensorboard.stop import TensorboardConfig 11 | from lightning_training_studio.controllers.controller import ControllerResource 12 | from lightning_training_studio.utilities.enum import Stage 13 | 14 | 15 | class Tensorboard(LightningWork, ControllerResource): 16 | model = TensorboardConfig 17 | 18 | def __init__(self, *args, drive: Drive, config: TensorboardConfig, **kwargs): 19 | super().__init__(*args, parallel=True, **kwargs) 20 | self.drive = drive 21 | self.sweep_id = config.sweep_id 22 | self.shared_folder = config.shared_folder 23 | self.stage = config.stage 24 | self.desired_stage = config.desired_stage 25 | self.config = config.dict() 26 | self._process = None 27 | self.downloaded_file = False 28 | 29 | def run(self): 30 | use_localhost = "LIGHTNING_APP_STATE_URL" not in os.environ 31 | local_folder = f"./tensorboard_logs/{uuid4()}" 32 | os.makedirs(local_folder, exist_ok=True) 33 | fs = _filesystem() 34 | root_folder = str(self.drive.drive_root) 35 | extras = "--reload_interval 1 --reload_multifile True" 36 | 37 | while True: 38 | fs.invalidate_cache() 39 | for dir, _, files in fs.walk(root_folder): 40 | for filepath in files: 41 | if "events.out.tfevents" not in filepath: 42 | continue 43 | source_path = os.path.join(dir, filepath) 44 | target_path = os.path.join(dir, filepath).replace(root_folder, local_folder) 45 | if use_localhost: 46 | parent = Path(target_path).resolve().parent 47 | if not parent.exists(): 48 | parent.mkdir(exist_ok=True, parents=True) 49 | fs.get(source_path, str(Path(target_path).resolve())) 50 | if not self.downloaded_file: 51 | self.downloaded_file = True 52 | if self.downloaded_file and self._process is None: 53 | cmd = f"tensorboard --logdir={local_folder} --host {self.host} --port {self.port} {extras}" 54 | self._process = Popen(cmd, shell=True, env=os.environ) 55 | self.stage = Stage.RUNNING 56 | 57 | def on_exit(self): 58 | assert self._process 59 | self._process.kill() 60 | 61 | def on_collect_model(self, model_dict): 62 | model_dict["url"] = self.url 63 | -------------------------------------------------------------------------------- /lightning_training_studio/controllers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/lightning_training_studio/controllers/__init__.py -------------------------------------------------------------------------------- /lightning_training_studio/distributions/__init__.py: -------------------------------------------------------------------------------- 1 | from lightning_training_studio.distributions.distributions import * # noqa F403 F401 2 | -------------------------------------------------------------------------------- /lightning_training_studio/distributions/distributions.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | from typing import Any, Dict, List, Optional, TypedDict 3 | 4 | 5 | class DistributionDict(TypedDict): 6 | distribution: str 7 | params: Dict[str, Any] 8 | 9 | 10 | class Distribution(ABC): 11 | @abstractmethod 12 | def to_dict(self) -> DistributionDict: 13 | ... 14 | 15 | 16 | class LogUniform(Distribution): 17 | def __init__(self, low: float, high: float) -> None: 18 | self.low = low 19 | self.high = high 20 | 21 | def to_dict(self) -> DistributionDict: 22 | return {"distribution": "log_uniform", "params": {"low": self.low, "high": self.high}} 23 | 24 | 25 | class Uniform(Distribution): 26 | def __init__(self, low: float, high: float) -> None: 27 | self.low = low 28 | self.high = high 29 | 30 | def to_dict(self): 31 | return {"distribution": "uniform", "params": {"low": self.low, "high": self.high}} 32 | 33 | 34 | class Categorical(Distribution): 35 | def __init__(self, choices: List[Any]) -> None: 36 | self.choices = choices 37 | 38 | def to_dict(self) -> DistributionDict: 39 | return {"distribution": "categorical", "params": {"choices": self.choices}} 40 | 41 | 42 | class IntUniform(Distribution): 43 | def __init__(self, low: int, high: int, step: Optional[int] = 1) -> None: 44 | self.low = low 45 | self.high = high 46 | self.step = step 47 | 48 | def to_dict(self) -> DistributionDict: 49 | return {"distribution": "int_uniform", "params": {"low": self.low, "high": self.high, "step": self.step}} 50 | -------------------------------------------------------------------------------- /lightning_training_studio/framework/__init__.py: -------------------------------------------------------------------------------- 1 | from lightning_training_studio.framework.agnostic import Objective 2 | from lightning_training_studio.framework.pytorch_lightning import ObjectiveLightningTrainingComponent 3 | 4 | _OBJECTIVE_FRAMEWORK = {"base": Objective, "pytorch_lightning": ObjectiveLightningTrainingComponent} 5 | -------------------------------------------------------------------------------- /lightning_training_studio/loggers/__init__.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | from lightning_training_studio.loggers.logger import Logger, NoneLogger 4 | from lightning_training_studio.loggers.streamlit.streamlit import StreamLitLogger 5 | from lightning_training_studio.loggers.tensorboard import TensorboardLogger 6 | from lightning_training_studio.loggers.wandb import WandbLogger 7 | 8 | 9 | class LoggerType(Enum): 10 | STREAMLIT = "streamlit" 11 | WANDB = "wandb" 12 | TENSORBOARD = "tensorboard" 13 | NONE = "none" 14 | 15 | def get_logger(self) -> Logger: 16 | if self == LoggerType.NONE: 17 | return NoneLogger() 18 | if self == LoggerType.STREAMLIT: 19 | return StreamLitLogger() 20 | elif self == LoggerType.WANDB: 21 | return WandbLogger() 22 | elif self == LoggerType.TENSORBOARD: 23 | return TensorboardLogger() 24 | else: 25 | raise ValueError("Unknown runtime type") 26 | -------------------------------------------------------------------------------- /lightning_training_studio/loggers/logger.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | from typing import Any, Dict, List, Optional 3 | 4 | from lightning import LightningFlow 5 | from lightning.app.utilities.tracer import Tracer 6 | 7 | 8 | class Logger(ABC): 9 | def on_after_experiment_start(self, sweep_id: str): 10 | ... 11 | 12 | @abstractmethod 13 | def on_after_experiment_end( 14 | self, sweep_id: str, experiment_id: int, monitor: Optional[str], score: Optional[float], params: Dict[str, Any] 15 | ): 16 | ... 17 | 18 | @abstractmethod 19 | def connect(self, flow: LightningFlow): 20 | ... 21 | 22 | @abstractmethod 23 | def configure_layout(self) -> Dict[str, Any]: 24 | ... 25 | 26 | @abstractmethod 27 | def configure_tracer(self, tracer, sweep_id: str, experiment_id: int, experiment_name: str, params: Dict[str, Any]): 28 | ... 29 | 30 | @abstractmethod 31 | def get_url(self, experiment_id: int) -> Optional[str]: 32 | ... 33 | 34 | 35 | class NoneLogger(Logger): 36 | def on_after_experiment_start(self, sweep_id: str): 37 | pass 38 | 39 | def on_after_experiment_end(self, *args, **kwargs): 40 | pass 41 | 42 | def connect(self, flow: LightningFlow): 43 | pass 44 | 45 | def configure_layout(self) -> List: 46 | return [] 47 | 48 | def configure_tracer(self, tracer, sweep_id: str, experiment_id: int, params: Dict[str, Any]): 49 | return Tracer() 50 | 51 | def get_url(self, experiment_id: int) -> Optional[str]: 52 | pass 53 | -------------------------------------------------------------------------------- /lightning_training_studio/loggers/streamlit/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/lightning_training_studio/loggers/streamlit/__init__.py -------------------------------------------------------------------------------- /lightning_training_studio/loggers/streamlit/hyperplot.py: -------------------------------------------------------------------------------- 1 | from lightning import LightningFlow 2 | from lightning.app.frontend.stream_lit import StreamlitFrontend 3 | from lightning.app.utilities.state import AppState 4 | 5 | 6 | class HiPlotFlow(LightningFlow): 7 | def __init__(self): 8 | super().__init__() 9 | self.data = [] 10 | 11 | def configure_layout(self): 12 | return StreamlitFrontend(render_fn=render_fn) 13 | 14 | 15 | def render_fn(state: AppState): 16 | import json 17 | 18 | import hiplot as hip 19 | import streamlit as st 20 | 21 | st.set_page_config(layout="wide") 22 | 23 | if not state.data: 24 | st.write("No data available yet ! Stay tuned") 25 | return 26 | 27 | xp = hip.Experiment.from_iterable(state.data) 28 | ret_val = xp.to_streamlit(ret="selected_uids", key="hip").display() 29 | st.markdown("hiplot returned " + json.dumps(ret_val)) 30 | -------------------------------------------------------------------------------- /lightning_training_studio/loggers/streamlit/streamlit.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Dict 2 | 3 | from lightning import LightningFlow 4 | 5 | from lightning_training_studio.loggers.logger import Logger 6 | from lightning_training_studio.loggers.streamlit.hyperplot import HiPlotFlow 7 | 8 | 9 | class StreamLitLogger(Logger): 10 | def __init__(self): 11 | super().__init__() 12 | self.hi_plot = HiPlotFlow() 13 | 14 | def on_after_experiment_end( 15 | self, sweep_id: str, experiment_id: int, monitor: str, score: float, params: Dict[str, Any] 16 | ): 17 | self.hi_plot.data.append({monitor: score, **params}) 18 | 19 | def connect(self, flow: LightningFlow): 20 | flow.hi_plot = self.hi_plot 21 | 22 | def configure_layout(self): 23 | return [{"name": "Experiment", "content": self.hi_plot}] 24 | 25 | def configure_tracer(self, tracer, sweep_id: str, experiment_id: int, experiment_name: str, params: Dict[str, Any]): 26 | pass 27 | 28 | def get_url(self, experiment_id: int) -> None: 29 | return None 30 | -------------------------------------------------------------------------------- /lightning_training_studio/utilities/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/lightning_training_studio/utilities/__init__.py -------------------------------------------------------------------------------- /lightning_training_studio/utilities/enum.py: -------------------------------------------------------------------------------- 1 | class Stage: 2 | NOT_STARTED = "not_started" 3 | PENDING = "pending" 4 | RUNNING = "running" 5 | PRUNED = "pruned" 6 | SUCCEEDED = "succeeded" 7 | FAILED = "failed" 8 | STOPPED = "stopped" 9 | STOPPING = "stopping" 10 | DELETED = "deleted" 11 | -------------------------------------------------------------------------------- /lightning_training_studio/utilities/imports.py: -------------------------------------------------------------------------------- 1 | from lightning_utilities.core.imports import RequirementCache 2 | 3 | _IS_WANDB_AVAILABLE = RequirementCache("wandb") 4 | _IS_PYTORCH_LIGHTNING_AVAILABLE = RequirementCache("pytorch_lightning") 5 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | jsonargparse[signatures] 2 | pytorch_lightning==1.8.6 3 | lightning==1.8.6 4 | lightning-jupyter 5 | torchvision 6 | optuna 7 | sqlmodel 8 | wandb 9 | streamlit 10 | sqlalchemy 11 | hiplot 12 | scikit-learn 13 | sqlite_web 14 | hydra-core 15 | tensorboard 16 | -------------------------------------------------------------------------------- /requirements/docs.txt: -------------------------------------------------------------------------------- 1 | sphinx>=4.0, <5.0 2 | myst-parser>=0.15, <0.17 3 | nbsphinx>=0.8.5, <=0.8.9 4 | pandoc>=1.0, <=2.2 5 | docutils>=0.16, <0.19 6 | sphinxcontrib-fulltoc>=1.0, <=1.2.0 7 | sphinxcontrib-mockautodoc 8 | sphinx-autodoc-typehints>=1.11, <1.15 # strict; v1.15 failing on master (#11405) 9 | sphinx-paramlinks>=0.5.1, <=0.5.4 10 | sphinx-togglebutton>=0.2, <=0.3.2 11 | sphinx-copybutton>=0.3, <=0.5.0 12 | sphinx-multiproject 13 | jinja2>=3.0.0,<3.1.0 14 | ipython[notebook] 15 | ipython_genutils 16 | sphinx-autobuild 17 | lai-sphinx-theme 18 | -------------------------------------------------------------------------------- /requirements/test.txt: -------------------------------------------------------------------------------- 1 | coverage>=6.4 2 | codecov>=2.1 3 | pytest>=7.0 4 | pytest-cov 5 | pytest-forked 6 | pytest-rerunfailures>=10.2 7 | mypy>=0.920 8 | flake8>=3.9.2 9 | pre-commit>=1.0 10 | psutil # for `DeviceStatsMonitor` 11 | playwright 12 | behave 13 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | from importlib.util import module_from_spec, spec_from_file_location 5 | 6 | from setuptools import find_packages, setup 7 | 8 | _PATH_ROOT = os.path.dirname(__file__) 9 | 10 | 11 | def _load_py_module(fname, pkg="lightning_training_studio"): 12 | spec = spec_from_file_location(os.path.join(pkg, fname), os.path.join(_PATH_ROOT, pkg, fname)) 13 | py = module_from_spec(spec) 14 | spec.loader.exec_module(py) 15 | return py 16 | 17 | 18 | about = _load_py_module("__about__.py") 19 | setup_tools = _load_py_module("setup_tools.py") 20 | long_description = setup_tools._load_readme_description(_PATH_ROOT, homepage=about.__homepage__, ver=about.__version__) 21 | 22 | # https://packaging.python.org/discussions/install-requires-vs-requirements / 23 | # keep the meta-data here for simplicity in reading this file... it's not obvious 24 | # what happens and to non-engineers they won't know to look in init ... 25 | # the goal of the project is simplicity for researchers, don't want to add too much 26 | # engineer specific practices 27 | 28 | setup( 29 | name="lightning_training_studio", 30 | version=about.__version__, 31 | description=about.__docs__, 32 | author=about.__author__, 33 | author_email=about.__author_email__, 34 | url=about.__homepage__, 35 | download_url="https://github.com/Lightning-AI/lightning-hpo", 36 | license=about.__license__, 37 | packages=find_packages(exclude=["tests", "docs"]), 38 | long_description=long_description, 39 | long_description_content_type="text/markdown", 40 | include_package_data=True, 41 | zip_safe=False, 42 | keywords=["deep learning", "pytorch", "AI"], 43 | python_requires=">=3.6", 44 | entry_points={}, 45 | setup_requires=["wheel"], 46 | install_requires=setup_tools._load_requirements(_PATH_ROOT), 47 | ) 48 | -------------------------------------------------------------------------------- /sweep_examples/1_app_agnostic.py: -------------------------------------------------------------------------------- 1 | import os.path as ops 2 | 3 | from lightning import LightningApp 4 | 5 | from lightning_training_studio import Sweep 6 | from lightning_training_studio.distributions.distributions import Uniform 7 | 8 | app = LightningApp( 9 | Sweep( 10 | script_path=ops.join(ops.dirname(__file__), "scripts/objective.py"), 11 | total_experiments=3, 12 | parallel_experiments=1, 13 | direction="maximize", 14 | distributions={"x": Uniform(-10, 10)}, 15 | ) 16 | ) 17 | -------------------------------------------------------------------------------- /sweep_examples/2_app_pytorch_lightning.py: -------------------------------------------------------------------------------- 1 | import os.path as ops 2 | 3 | import optuna 4 | from lightning import LightningApp 5 | 6 | from lightning_training_studio import Sweep 7 | from lightning_training_studio.algorithm.optuna import OptunaAlgorithm 8 | from lightning_training_studio.distributions.distributions import Categorical, IntUniform, LogUniform, Uniform 9 | 10 | app = LightningApp( 11 | Sweep( 12 | script_path=ops.join(ops.dirname(__file__), "scripts/train.py"), 13 | total_experiments=3, 14 | parallel_experiments=1, 15 | distributions={ 16 | "--model.lr": LogUniform(0.001, 0.1), 17 | "--model.gamma": Uniform(0.5, 0.8), 18 | "--data.batch_size": Categorical([16, 32, 64]), 19 | "--trainer.max_epochs": IntUniform(1, 5), 20 | }, 21 | algorithm=OptunaAlgorithm(optuna.create_study(direction="maximize")), 22 | framework="pytorch_lightning", 23 | ) 24 | ) 25 | -------------------------------------------------------------------------------- /sweep_examples/3_app_sklearn.py: -------------------------------------------------------------------------------- 1 | import optuna 2 | from lightning import LightningApp 3 | from sklearn import datasets 4 | from sklearn.linear_model import SGDClassifier 5 | from sklearn.model_selection import train_test_split 6 | 7 | from lightning_training_studio import Objective, Sweep 8 | from lightning_training_studio.algorithm.optuna import OptunaAlgorithm 9 | from lightning_training_studio.distributions.distributions import LogUniform 10 | 11 | 12 | class MyObjective(Objective): 13 | def objective(self, alpha: float): 14 | iris = datasets.load_iris() 15 | classes = list(set(iris.target)) 16 | train_x, valid_x, train_y, valid_y = train_test_split( 17 | iris.data, 18 | iris.target, 19 | test_size=0.25, 20 | random_state=0, 21 | ) 22 | 23 | clf = SGDClassifier(alpha=alpha) 24 | 25 | self.monitor = "accuracy" 26 | 27 | for step in range(100): 28 | clf.partial_fit(train_x, train_y, classes=classes) 29 | intermediate_value = clf.score(valid_x, valid_y) 30 | 31 | # WARNING: Assign to reports, 32 | # so the state is instantly sent to the flow. 33 | self.reports = self.reports + [[intermediate_value, step]] 34 | 35 | self.best_model_score = clf.score(valid_x, valid_y) 36 | self.has_finished = True 37 | 38 | 39 | app = LightningApp( 40 | Sweep( 41 | objective_cls=MyObjective, 42 | total_experiments=20, 43 | parallel_experiments=1, 44 | algorithm=OptunaAlgorithm( 45 | optuna.create_study( 46 | pruner=optuna.pruners.MedianPruner(), 47 | direction="maximize", 48 | ) 49 | ), 50 | distributions={"alpha": LogUniform(1e-5, 1e-1)}, 51 | ) 52 | ) 53 | -------------------------------------------------------------------------------- /sweep_examples/4_app_grid_search.py: -------------------------------------------------------------------------------- 1 | import os.path as ops 2 | 3 | from lightning import LightningApp 4 | 5 | from lightning_training_studio import Sweep 6 | from lightning_training_studio.algorithm import GridSearch 7 | 8 | app = LightningApp( 9 | Sweep( 10 | script_path=ops.join(ops.dirname(__file__), "scripts/objective.py"), 11 | total_experiments=3, 12 | parallel_experiments=1, 13 | algorithm=GridSearch(search_space={"x": [-10, 0, 10]}), 14 | ) 15 | ) 16 | -------------------------------------------------------------------------------- /sweep_examples/5_app_random_search.py: -------------------------------------------------------------------------------- 1 | import os.path as ops 2 | 3 | from lightning import LightningApp 4 | 5 | from lightning_training_studio import Sweep 6 | from lightning_training_studio.algorithm import RandomSearch 7 | from lightning_training_studio.distributions import Uniform 8 | 9 | app = LightningApp( 10 | Sweep( 11 | script_path=ops.join(ops.dirname(__file__), "scripts/objective.py"), 12 | total_experiments=3, 13 | parallel_experiments=1, 14 | algorithm=RandomSearch(distributions={"x": Uniform(-10, 10)}), 15 | ) 16 | ) 17 | -------------------------------------------------------------------------------- /sweep_examples/requirements.txt: -------------------------------------------------------------------------------- 1 | lightning-hpo 2 | -------------------------------------------------------------------------------- /sweep_examples/scripts/.lightningignore: -------------------------------------------------------------------------------- 1 | *lightning_logs* 2 | .shared 3 | *.ckpt 4 | *.shared* 5 | *.git* 6 | *MNIST* 7 | *egg-info/* 8 | *model_weight.pt* 9 | *cifar-10-batches-py* 10 | flagged 11 | wandb 12 | .venv 13 | thomas-* 14 | venv 15 | dist 16 | tensorboard_logs 17 | jupyter_lab_* 18 | *node_modules* 19 | docs 20 | .storage 21 | .coverage 22 | coverage.xml 23 | LICENSE 24 | spec.json 25 | database.db 26 | examples 27 | data/* 28 | -------------------------------------------------------------------------------- /sweep_examples/scripts/big_model.py: -------------------------------------------------------------------------------- 1 | import pytorch_lightning as pl 2 | from lightning_transformers.task.nlp.language_modeling import LanguageModelingDataModule, LanguageModelingTransformer 3 | from transformers import AutoTokenizer 4 | 5 | model_name = "gpt2-xl" 6 | 7 | tokenizer = AutoTokenizer.from_pretrained(model_name) 8 | 9 | model = LanguageModelingTransformer( 10 | pretrained_model_name_or_path=model_name, 11 | tokenizer=tokenizer, 12 | deepspeed_sharding=True, # defer initialization of the model to shard/load pre-train weights 13 | ) 14 | 15 | dm = LanguageModelingDataModule( 16 | batch_size=1, 17 | dataset_name="wikitext", 18 | dataset_config_name="wikitext-2-raw-v1", 19 | tokenizer=tokenizer, 20 | ) 21 | trainer = pl.Trainer( 22 | accelerator="auto", 23 | devices="auto", 24 | strategy="deepspeed_stage_3", 25 | precision=16, 26 | max_epochs=20, 27 | ) 28 | 29 | trainer.fit(model, dm) 30 | -------------------------------------------------------------------------------- /sweep_examples/scripts/data.py: -------------------------------------------------------------------------------- 1 | import glob 2 | 3 | # 1: Add dataset from s3. 4 | # python -m lightning add dataset --name example --source s3://pl-flash-data/wiki-test/ 5 | 6 | # 2: Attach the Data to an experiment 7 | # python -m lightning run experiment data.py --dataset example 8 | 9 | for filename in glob.iglob("/data/example/**/**", recursive=True): 10 | print(filename) 11 | -------------------------------------------------------------------------------- /sweep_examples/scripts/objective.py: -------------------------------------------------------------------------------- 1 | def objective(x: float): 2 | return (x - 2) ** 2 3 | -------------------------------------------------------------------------------- /sweep_examples/scripts/requirements.txt: -------------------------------------------------------------------------------- 1 | pytorch_lightning 2 | 'jsonargparse[signatures]' 3 | torchvision 4 | -------------------------------------------------------------------------------- /sweep_examples/scripts/train_cifar.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import pytorch_lightning as pl 4 | import torch 5 | import torch.nn.functional as F 6 | from torch.utils.data import DataLoader 7 | from torchmetrics.functional import accuracy 8 | from torchvision import transforms 9 | from torchvision.datasets import CIFAR10 10 | 11 | 12 | class LitModel(pl.LightningModule): 13 | def __init__(self, lr: float = 0.0001, batch_size: int = 32): 14 | super().__init__() 15 | self.save_hyperparameters() 16 | self.layer_1 = torch.nn.Linear(3 * 32 * 32, 128) 17 | self.layer_2 = torch.nn.Linear(128, 10) 18 | 19 | def forward(self, x): 20 | x = x.view(x.size(0), -1) 21 | x = self.layer_1(x) 22 | x = F.relu(x) 23 | x = self.layer_2(x) 24 | x = F.log_softmax(x) 25 | return x 26 | 27 | def configure_optimizers(self): 28 | optimizer = torch.optim.Adam(self.parameters(), lr=self.hparams.lr) 29 | return optimizer 30 | 31 | def training_step(self, batch, batch_idx): 32 | x, y = batch 33 | y_hat = self(x) 34 | loss = F.nll_loss(y_hat, y) 35 | self.log("train_loss", loss) 36 | self.log("train_acc", accuracy(y_hat.exp(), y), prog_bar=True) 37 | return loss 38 | 39 | 40 | if __name__ == "__main__": 41 | from argparse import ArgumentParser 42 | 43 | parser = ArgumentParser() 44 | parser.add_argument("--gpus", type=int, default=None) 45 | parser.add_argument("--lr", type=float, default=1e-3) 46 | parser.add_argument("--batch_size", type=int, default=32) 47 | parser.add_argument("--max_epochs", type=int, default=10) 48 | parser.add_argument("--data_dir", type=str, default=os.getcwd()) 49 | args = parser.parse_args() 50 | 51 | dataset = CIFAR10(args.data_dir, download=True, transform=transforms.ToTensor()) 52 | train_loader = DataLoader(dataset, batch_size=args.batch_size) 53 | 54 | # init model 55 | model = LitModel(lr=args.lr) 56 | 57 | # most basic trainer, uses good defaults (auto-tensorboard, checkpoints, logs, and more) 58 | trainer = pl.Trainer(gpus=args.gpus, max_epochs=args.max_epochs) 59 | trainer.fit(model, train_loader) 60 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/tests/__init__.py -------------------------------------------------------------------------------- /tests/app/test_main.py: -------------------------------------------------------------------------------- 1 | from lightning.app.runners import MultiProcessRuntime 2 | from lightning.app.testing import LightningTestApp 3 | 4 | from lightning_training_studio.app.main import TrainingStudio 5 | from lightning_training_studio.controllers import controller 6 | from tests.helpers import MockDatabaseClient 7 | 8 | 9 | class MainLightningTestApp(LightningTestApp): 10 | def on_before_run_once(self): 11 | res = super().on_before_run_once() 12 | if self.root.ready: 13 | return True 14 | return res 15 | 16 | 17 | def test_main(monkeypatch): 18 | monkeypatch.setattr(controller, "DatabaseClient", MockDatabaseClient) 19 | 20 | flow = TrainingStudio() 21 | app = MainLightningTestApp(flow) 22 | MultiProcessRuntime(app).dispatch() 23 | -------------------------------------------------------------------------------- /tests/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/tests/commands/__init__.py -------------------------------------------------------------------------------- /tests/commands/artifacts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/tests/commands/artifacts/__init__.py -------------------------------------------------------------------------------- /tests/commands/artifacts/test_download.py: -------------------------------------------------------------------------------- 1 | import os 2 | import os.path as osp 3 | import sys 4 | import tempfile 5 | from pathlib import Path 6 | from unittest.mock import MagicMock 7 | 8 | import requests 9 | 10 | from lightning_training_studio.commands.artifacts.download import ( 11 | DownloadArtifactsCommand, 12 | DownloadArtifactsConfigResponse, 13 | ) 14 | 15 | 16 | def test_download_artifacts(monkeypatch, tmpdir): 17 | original_sys_argv = sys.argv 18 | 19 | with tempfile.TemporaryDirectory() as tmp: 20 | path = Path(osp.join(tmp, "a/something/drive/c/example.txt")) 21 | os.makedirs(path.parent, exist_ok=True) 22 | with open(path, "w") as f: 23 | f.write("example.txt") 24 | 25 | path = Path(osp.join(tmp, "e/d/drive/f/example.txt")) 26 | os.makedirs(path.parent, exist_ok=True) 27 | with open(path, "w") as f: 28 | f.write("example.txt") 29 | 30 | paths = [] 31 | for d, _, files in os.walk(tmp): 32 | for f in files: 33 | paths.append(osp.join(d, f)) 34 | 35 | resp = MagicMock() 36 | resp.json.return_value = DownloadArtifactsConfigResponse( 37 | paths=paths, sweep_names=[], experiment_names=["something"], urls=None 38 | ).dict() 39 | resp.status_code = 200 40 | post = MagicMock(return_value=resp) 41 | monkeypatch.setattr(requests, "post", post) 42 | 43 | output_dir = osp.join(str(tmpdir), "new_folder") 44 | os.makedirs(output_dir) 45 | sys.argv = ["", "--output_dir", output_dir, "--names", "something"] 46 | command = DownloadArtifactsCommand(None) 47 | command.command_name = "" 48 | command.app_url = "" 49 | command.run() 50 | assert osp.exists(osp.join(output_dir, "c/example.txt")) 51 | assert not osp.exists(osp.join(output_dir, "f/example.txt")) 52 | 53 | sys.argv = original_sys_argv 54 | -------------------------------------------------------------------------------- /tests/commands/artifacts/test_show.py: -------------------------------------------------------------------------------- 1 | import os 2 | import os.path as osp 3 | import sys 4 | import tempfile 5 | from pathlib import Path 6 | from unittest.mock import MagicMock 7 | 8 | import requests 9 | 10 | from lightning_training_studio.commands.artifacts import show 11 | from lightning_training_studio.commands.artifacts.show import ShowArtifactsCommand, ShowArtifactsConfigResponse 12 | 13 | 14 | def test_show_artifacts(monkeypatch, tmpdir): 15 | original_sys_argv = sys.argv 16 | 17 | with tempfile.TemporaryDirectory() as tmp: 18 | # 1: Create some shared files. 19 | path = Path(osp.join(tmp, "a/b/c/d/example.txt")) 20 | os.makedirs(path.parent, exist_ok=True) 21 | with open(path, "w") as f: 22 | f.write("example.txt") 23 | 24 | path = Path(osp.join(tmp, "d/a/b/c/example.txt")) 25 | os.makedirs(path.parent, exist_ok=True) 26 | with open(path, "w") as f: 27 | f.write("example.txt") 28 | 29 | paths = [] 30 | for d, _, files in os.walk(tmp): 31 | for f in files: 32 | paths.append(osp.join(d, f)) 33 | 34 | resp = MagicMock() 35 | resp.json.return_value = ShowArtifactsConfigResponse(sweep_names=[], experiment_names=["b"], paths=paths).dict() 36 | resp.status_code = 200 37 | post = MagicMock(return_value=resp) 38 | monkeypatch.setattr(requests, "post", post) 39 | 40 | monkeypatch.setattr(show, "_shared_storage_path", lambda: tmp) 41 | print_mock = MagicMock() 42 | monkeypatch.setattr(show.rich, "print", print_mock) 43 | 44 | output_dir = osp.join(str(tmpdir), ".shared/") 45 | os.makedirs(output_dir) 46 | sys.argv = ["", "--display_mode", "tree", "--names", "b"] 47 | command = ShowArtifactsCommand(None) 48 | command.command_name = "" 49 | command.app_url = "" 50 | command.run() 51 | 52 | tree = print_mock._mock_call_args.args[0] 53 | assert isinstance(tree, show.Tree) 54 | 55 | counter = 0 56 | has_checked = False 57 | while tree.children: 58 | tree = tree.children[0] 59 | counter += 1 60 | if len(tree.children) == 2: 61 | assert tree.children[0].label == "[bold magenta]:open_file_folder: a" 62 | assert tree.children[1].label == "[bold magenta]:open_file_folder: d" 63 | has_checked = True 64 | assert has_checked 65 | assert "📄 " in tree.label._text[0] 66 | 67 | sys.argv = original_sys_argv 68 | -------------------------------------------------------------------------------- /tests/commands/data/test_create.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from lightning_training_studio.commands.data.create import DataConfig 4 | 5 | 6 | def test_create_drive(): 7 | with pytest.raises(Exception, match='The `source` needs to start with "s3://"'): 8 | DataConfig(name="str", source="a", mount_path="b") 9 | 10 | with pytest.raises(Exception, match="The `source` needs to end with in a trailing slash"): 11 | DataConfig(name="str", source="s3://a", mount_path="b") 12 | 13 | with pytest.raises(Exception, match="The `mount_path` needs to start with a leading slash"): 14 | DataConfig(name="str", source="s3://a/", mount_path="b") 15 | 16 | with pytest.raises(Exception, match="The `mount_path` needs to end with in a trailing slash"): 17 | DataConfig(name="str", source="s3://a/", mount_path="/b") 18 | 19 | DataConfig(name="str", source="s3://a/", mount_path="/b/") 20 | -------------------------------------------------------------------------------- /tests/commands/experiment/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/tests/commands/experiment/__init__.py -------------------------------------------------------------------------------- /tests/commands/experiment/test_requirements: -------------------------------------------------------------------------------- 1 | pytorch_lightning 2 | optuna 3 | 4 | deepspeed 5 | -------------------------------------------------------------------------------- /tests/commands/experiment/test_stop.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | from copy import deepcopy 4 | from unittest.mock import MagicMock 5 | 6 | import requests 7 | from lightning.app.storage import Drive 8 | 9 | from lightning_training_studio.commands.experiment.stop import StopExperimentConfig 10 | from lightning_training_studio.components.sweep import Sweep, SweepConfig 11 | from lightning_training_studio.controllers.sweep import SweepController 12 | from lightning_training_studio.utilities.enum import Stage 13 | 14 | 15 | def test_stop_sweeps_experiment(monkeypatch): 16 | with open(os.path.join(os.path.dirname(__file__), "../sweep/sweep_1.json"), "rb") as f: 17 | data = json.load(f) 18 | 19 | sweep_config = SweepConfig(**data[0]) 20 | experiment = deepcopy(sweep_config.experiments[0]) 21 | experiment.stage = Stage.RUNNING 22 | sweep_config.experiments[1] = experiment 23 | sweep_config.logger = "streamlit" 24 | sweep = Sweep.from_config(config=sweep_config) 25 | 26 | sweep_controller = SweepController(Drive("lit://code")) 27 | sweep_controller._db_client = MagicMock() 28 | sweep_controller.r[sweep_config.sweep_id] = sweep 29 | resp = MagicMock() 30 | resp.status_code = 200 31 | monkeypatch.setattr(requests, "put", MagicMock(return_value=resp)) 32 | 33 | sweep_mock = MagicMock() 34 | sweep_mock.collect_model.return_value = sweep_config 35 | sweep_controller.r[sweep_config.sweep_id] = sweep_mock 36 | sweep_controller._db_client.select_all.return_value = [sweep_config] 37 | result = sweep_controller.stop_experiment(config=StopExperimentConfig(name="a")) 38 | assert result == "The current experiment `a` has been stopped." 39 | sweep_controller.r[sweep_config.sweep_id].stop_experiment.assert_called() 40 | result = sweep_controller.stop_experiment(config=StopExperimentConfig(name="aa")) 41 | assert result == "The current experiment `aa` doesn't exist." 42 | -------------------------------------------------------------------------------- /tests/commands/sweep/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/tests/commands/sweep/__init__.py -------------------------------------------------------------------------------- /tests/commands/sweep/sweep_1.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "requirements": "[]", 4 | "packages": "[]", 5 | "script_args": "[]", 6 | "distributions": {"model.lr": {"distribution": "uniform", "params": {"low": 0.001, "high": 0.1}}}, 7 | "experiments": {"0": {"name": "a", "best_model_score": 0.125, "monitor": "val_acc", "best_model_path": null, "status": "succeeded", "params": {"model.lr": 0.04490742315966646}, "exception": null, "start_time": null, "end_time": null, "total_parameters": null}, "1": {"name": "b", "best_model_score": 0.125, "monitor": "val_acc", "best_model_path": null, "status": "succeeded", "params": {"model.lr": 0.0860064559763192}, "exception": null, "start_time": null, "end_time": null, "total_parameters": null}, "2": {"name": "c", "best_model_score": 0.125, "monitor": "val_acc", "best_model_path": null, "status": "succeeded", "params": {"model.lr": 0.08511019485430553}, "exception": null, "start_time": null, "end_time": null, "total_parameters": null}}, 8 | "id": 1, 9 | "sweep_id": "thomas-cb8f69f0", 10 | "script_path": "train.py", 11 | "total_experiments": 3, 12 | "parallel_experiments": 1, 13 | "total_experiments_done": 3, 14 | "url": null, 15 | "framework": "pytorch_lightning", 16 | "cloud_compute": "cpu", 17 | "num_nodes": 1, 18 | "logger": "wandb", 19 | "direction": "maximize", 20 | "status": "succeeded", 21 | "shm_size": 1024, 22 | "disk_size": 80, 23 | "username": "", 24 | "artifacts_path": "" 25 | } 26 | ] 27 | -------------------------------------------------------------------------------- /tests/commands/sweep/test_delete.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | from copy import deepcopy 4 | from unittest.mock import MagicMock 5 | 6 | from lightning.app.storage import Drive 7 | 8 | from lightning_training_studio.commands.sweep.delete import DeleteSweepConfig 9 | from lightning_training_studio.components.sweep import Sweep, SweepConfig 10 | from lightning_training_studio.controllers.sweep import SweepController 11 | from lightning_training_studio.utilities.enum import Stage 12 | 13 | 14 | def test_delete_sweeps_server(monkeypatch, tmpdir): 15 | with open(os.path.join(os.path.dirname(__file__), "sweep_1.json"), "rb") as f: 16 | data = json.load(f) 17 | 18 | sweep_config = SweepConfig(**data[0]) 19 | experiment = deepcopy(sweep_config.experiments[0]) 20 | experiment.stage = Stage.RUNNING 21 | sweep_config.experiments[1] = experiment 22 | sweep_config.logger = "streamlit" 23 | sweep = Sweep.from_config(config=sweep_config) 24 | 25 | sweep_controller = SweepController(Drive("lit://code")) 26 | db = MagicMock() 27 | db.select_all.return_value = [sweep_config] 28 | sweep_controller._db_client = db 29 | sweep_controller.r[sweep_config.sweep_id] = sweep 30 | result = sweep_controller.delete_sweep(config=DeleteSweepConfig(name=sweep_config.sweep_id)) 31 | assert result == "Deleted the sweep `thomas-cb8f69f0`" 32 | assert sweep_controller.r == {} 33 | db.select_all.return_value = [] 34 | result = sweep_controller.delete_sweep(config=DeleteSweepConfig(name=sweep_config.sweep_id)) 35 | assert result == "We didn't find the sweep `thomas-cb8f69f0`" 36 | -------------------------------------------------------------------------------- /tests/commands/sweep/test_show.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import sys 4 | from unittest.mock import MagicMock 5 | 6 | import pytest 7 | import requests 8 | from lightning.app.storage import Drive 9 | from rich.table import Table 10 | 11 | from lightning_training_studio.commands.sweep import show 12 | from lightning_training_studio.commands.sweep.show import ShowSweepsCommand 13 | from lightning_training_studio.components.sweep import Sweep, SweepConfig 14 | from lightning_training_studio.controllers.sweep import SweepController 15 | 16 | 17 | def test_show_sweeps_client(monkeypatch): 18 | ori_sys_argv = sys.argv 19 | 20 | with open(os.path.join(os.path.dirname(__file__), "sweep_1.json"), "rb") as f: 21 | data = json.load(f) 22 | 23 | resp = MagicMock() 24 | resp.json.return_value = data 25 | resp.status_code = 200 26 | monkeypatch.setattr(requests, "post", MagicMock(return_value=resp)) 27 | console = MagicMock() 28 | 29 | monkeypatch.setattr(show, "Console", console) 30 | sys.argv = [""] 31 | command = ShowSweepsCommand(None) 32 | command.command_name = "" 33 | command.app_url = "" 34 | command.run() 35 | assert len(console._mock_mock_calls) == 2 36 | table = console._mock_mock_calls[1].args[0] 37 | assert isinstance(table, Table) 38 | assert table.columns[0]._cells == ["thomas-cb8f69f0"] 39 | 40 | monkeypatch.setattr(show, "Console", console) 41 | with pytest.raises(Exception, match="thomas-cb8f69f0"): 42 | sys.argv = ["", "--name=1234"] 43 | command = ShowSweepsCommand(None) 44 | command.command_name = "" 45 | command.app_url = "" 46 | command.run() 47 | 48 | monkeypatch.setattr(show, "Console", console) 49 | sys.argv = ["", "--name=thomas-cb8f69f0"] 50 | command = ShowSweepsCommand(None) 51 | command.command_name = "" 52 | command.app_url = "" 53 | command.run() 54 | assert len(console._mock_mock_calls) == 4 55 | table = console._mock_mock_calls[-1].args[0] 56 | assert isinstance(table, Table) 57 | assert table.columns[3]._cells[0] == "3" 58 | 59 | sys.argv = ori_sys_argv 60 | 61 | 62 | def test_show_sweeps_server(): 63 | with open(os.path.join(os.path.dirname(__file__), "sweep_1.json"), "rb") as f: 64 | data = json.load(f) 65 | 66 | sweep_config = SweepConfig(**data[0]) 67 | sweep_config.logger = "streamlit" 68 | Sweep.from_config(config=sweep_config) 69 | 70 | sweep_controller = SweepController(Drive("lit://code")) 71 | sweep_controller._db_client = MagicMock() 72 | sweep_controller.db_url = "a" 73 | sweep_controller._db_client.select_all.return_value = [sweep_config] 74 | result = sweep_controller.show_sweeps() 75 | assert result[0] == sweep_config.dict() 76 | -------------------------------------------------------------------------------- /tests/commands/sweep/test_stop.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | from copy import deepcopy 4 | from unittest.mock import MagicMock 5 | 6 | import requests 7 | from lightning.app.storage import Drive 8 | 9 | from lightning_training_studio.commands.sweep.stop import StopSweepConfig 10 | from lightning_training_studio.components.sweep import Sweep, SweepConfig 11 | from lightning_training_studio.controllers.sweep import SweepController 12 | from lightning_training_studio.utilities.enum import Stage 13 | 14 | 15 | def test_stop_sweeps_server(monkeypatch): 16 | with open(os.path.join(os.path.dirname(__file__), "sweep_1.json"), "rb") as f: 17 | data = json.load(f) 18 | 19 | sweep_config = SweepConfig(**data[0]) 20 | experiment = deepcopy(sweep_config.experiments[0]) 21 | experiment.stage = Stage.RUNNING 22 | sweep_config.experiments[1] = experiment 23 | sweep_config.logger = "streamlit" 24 | sweep = Sweep.from_config(config=sweep_config) 25 | 26 | sweep_controller = SweepController(Drive("lit://code")) 27 | sweep_controller._db_client = MagicMock() 28 | sweep_controller.r[sweep_config.sweep_id] = sweep 29 | resp = MagicMock() 30 | resp.status_code = 200 31 | monkeypatch.setattr(requests, "post", MagicMock(return_value=resp)) 32 | 33 | sweep_mock = MagicMock() 34 | sweep_mock.collect_model.return_value = sweep_config 35 | sweep_controller.r[sweep_config.sweep_id] = sweep_mock 36 | result = sweep_controller.stop_sweep(config=StopSweepConfig(sweep_id=sweep_config.sweep_id)) 37 | assert result == "Stopped the sweep `thomas-cb8f69f0`" 38 | sweep_mock.stop.assert_called() 39 | -------------------------------------------------------------------------------- /tests/components/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/tests/components/__init__.py -------------------------------------------------------------------------------- /tests/components/test_tensorboard.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from lightning.app.storage import Drive 3 | 4 | from lightning_training_studio.commands.tensorboard.stop import TensorboardConfig 5 | from lightning_training_studio.components import tensorboard as T 6 | 7 | 8 | def test_tensorboard_work(monkeypatch): 9 | def fn(*_, **__): 10 | raise Exception("HERE") 11 | 12 | monkeypatch.setattr(T, "Popen", fn) 13 | 14 | config = TensorboardConfig(id=0, sweep_id="1", shared_folder="") 15 | drive = Drive("lit://a") 16 | tensorboard = T.Tensorboard(drive=drive, config=config) 17 | tensorboard.downloaded_file = True 18 | with pytest.raises(Exception, match="HERE"): 19 | tensorboard.run() 20 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import threading 4 | from threading import Thread 5 | 6 | import psutil 7 | import pytest 8 | from lightning.app.storage.path import _storage_root_dir 9 | from lightning.app.utilities.component import _set_context 10 | from lightning.app.utilities.packaging.app_config import _APP_CONFIG_FILENAME 11 | 12 | original_method = Thread._wait_for_tstate_lock 13 | 14 | 15 | def fn(self, *args, timeout=None, **kwargs): 16 | original_method(self, *args, timeout=1, **kwargs) 17 | 18 | 19 | Thread._wait_for_tstate_lock = fn 20 | 21 | 22 | def pytest_sessionfinish(session, exitstatus): 23 | """Pytest hook that get called after whole test run finished, right before returning the exit status to the 24 | system.""" 25 | # kill all the processes and threads created by parent 26 | # TODO This isn't great. We should have each tests doing it's own cleanup 27 | current_process = psutil.Process() 28 | for child in current_process.children(recursive=True): 29 | try: 30 | params = child.as_dict() or {} 31 | cmd_lines = params.get("cmdline", []) 32 | # we shouldn't kill the resource tracker from multiprocessing. If we do, 33 | # `atexit` will throw as it uses resource tracker to try to clean up 34 | if cmd_lines and "resource_tracker" in cmd_lines[-1]: 35 | continue 36 | child.kill() 37 | except Exception: 38 | pass 39 | 40 | main_thread = threading.current_thread() 41 | for t in threading.enumerate(): 42 | if t is not main_thread: 43 | t.join(0) 44 | 45 | 46 | @pytest.fixture(scope="function", autouse=True) 47 | def cleanup(): 48 | from lightning.app.utilities.app_helpers import _LightningAppRef 49 | 50 | yield 51 | _LightningAppRef._app_instance = None 52 | shutil.rmtree("./storage", ignore_errors=True) 53 | shutil.rmtree(_storage_root_dir(), ignore_errors=True) 54 | shutil.rmtree("./.shared", ignore_errors=True) 55 | if os.path.isfile(_APP_CONFIG_FILENAME): 56 | os.remove(_APP_CONFIG_FILENAME) 57 | _set_context(None) 58 | -------------------------------------------------------------------------------- /tests/controllers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/tests/controllers/__init__.py -------------------------------------------------------------------------------- /tests/controllers/test_tensorboard.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import MagicMock 2 | 3 | from lightning_training_studio.commands.tensorboard.stop import TensorboardConfig 4 | from lightning_training_studio.controllers import controller, tensorboard 5 | from lightning_training_studio.controllers.tensorboard import TensorboardController 6 | from lightning_training_studio.utilities.enum import Stage 7 | from tests.helpers import MockDatabaseClient 8 | 9 | 10 | def test_tensorboard_controller(monkeypatch): 11 | tensorboard_controller = TensorboardController() 12 | monkeypatch.setattr(controller, "DatabaseClient", MockDatabaseClient) 13 | run = MagicMock() 14 | delete = MagicMock() 15 | monkeypatch.setattr(tensorboard.Tensorboard, "run", run) 16 | monkeypatch.setattr(tensorboard.Tensorboard, "delete", delete) 17 | monkeypatch.setattr(tensorboard.Tensorboard, "_check_run_is_implemented", lambda x: None) 18 | tensorboard_controller.run("a", "b") 19 | assert tensorboard_controller.db.data == {} 20 | 21 | config = TensorboardConfig(id=1, sweep_id="a", shared_folder="s") 22 | response = tensorboard_controller.run_tensorboard(config) 23 | assert response == "Launched a Tensorboard `a`." 24 | assert len(tensorboard_controller.db.data) == 1 25 | config: TensorboardConfig = tensorboard_controller.db.select_all()[0] 26 | assert config.stage == Stage.NOT_STARTED 27 | assert config.desired_stage == Stage.RUNNING 28 | 29 | run.assert_not_called() 30 | tensorboard_controller.run("a", "b") 31 | run.assert_called() 32 | tensorboard_controller.r["a"]._backend = MagicMock() 33 | tensorboard_obj_1 = tensorboard_controller.r["a"] 34 | assert isinstance(tensorboard_obj_1, tensorboard.Tensorboard) 35 | assert tensorboard_obj_1.collect_model() != config 36 | assert tensorboard_obj_1.collect_model().stage == Stage.PENDING 37 | 38 | tensorboard_obj_1._url = "abc" 39 | tensorboard_controller.run("a", "b") 40 | assert tensorboard_obj_1.stage == Stage.PENDING 41 | 42 | delete.assert_not_called() 43 | response = tensorboard_controller.stop_tensorboard(config) 44 | delete.assert_called() 45 | assert response == "Tensorboard `a` was stopped." 46 | assert tensorboard_controller.r == {} 47 | config = tensorboard_controller.db.select_all()[0] 48 | assert config.stage == Stage.STOPPED 49 | assert config.desired_stage == Stage.STOPPED 50 | 51 | response = tensorboard_controller.run_tensorboard(config) 52 | config = tensorboard_controller.db.select_all()[0] 53 | assert config.stage == Stage.STOPPED 54 | assert config.desired_stage == Stage.RUNNING 55 | assert response == "Re-Launched a Tensorboard `a`." 56 | tensorboard_controller.run("a", "b") 57 | assert isinstance(tensorboard_controller.r["a"], tensorboard.Tensorboard) 58 | assert tensorboard_controller.r["a"] != tensorboard_obj_1 59 | -------------------------------------------------------------------------------- /tests/features/environment.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | import sys 4 | import tempfile 5 | import time 6 | 7 | import psutil 8 | from behave import fixture, use_fixture 9 | from lightning.app.cli.lightning_cli import get_app_url 10 | from lightning.app.runners.runtime_type import RuntimeType 11 | from playwright.sync_api import expect, sync_playwright 12 | 13 | from lightning_training_studio import _PROJECT_ROOT 14 | 15 | 16 | def kill(proc_pid): 17 | process = psutil.Process(proc_pid) 18 | for proc in process.children(recursive=True): 19 | proc.kill() 20 | process.kill() 21 | 22 | 23 | @fixture 24 | def run_app(context): 25 | cmd = [ 26 | sys.executable, 27 | "-m", 28 | "lightning", 29 | "run", 30 | "app", 31 | os.path.join(_PROJECT_ROOT, "app.py"), 32 | "--open-ui", 33 | "False", 34 | ] 35 | 36 | with tempfile.TemporaryDirectory() as tmpdir: 37 | os.chmod(tmpdir, 0o777) 38 | # TODO: Doesn't work if you pass tmpdir as cwd to the Popen call 39 | os.chdir(tmpdir) 40 | process = subprocess.Popen(cmd, env=os.environ.copy(), preexec_fn=os.setsid) 41 | 42 | context.app_id = "localhost" 43 | 44 | with sync_playwright() as p: 45 | context.browser = p.chromium.launch() 46 | context.page = context.browser.new_page() 47 | 48 | while True: 49 | try: 50 | time.sleep(5) 51 | context.page.goto(get_app_url(RuntimeType.MULTIPROCESS)) 52 | locator = context.page.frame_locator("iframe").locator("text=Training Studio") 53 | expect(locator).to_be_visible(timeout=30 * 1000) 54 | break 55 | except: # noqa: E722 56 | pass 57 | 58 | yield context.browser 59 | 60 | context.browser.close() 61 | 62 | print("Killing App Process") 63 | kill(process.pid) 64 | 65 | 66 | def before_scenario(context, scenario): 67 | use_fixture(run_app, context) 68 | -------------------------------------------------------------------------------- /tests/features/notebook.feature: -------------------------------------------------------------------------------- 1 | Feature: Notebooks 2 | As an app user, 3 | I want to start a jupyter interactive session on a instance type of my choice, 4 | so that I can develop and run my model, or explore my data or artifacts. 5 | 6 | Scenario: Start notebook from the CLI 7 | Given I am connected to the app 8 | When I execute lightning run notebook 9 | Then I can see a notebook in the UI 10 | And the notebook status in the UI is running 11 | And I can open the notebook 12 | When I execute lightning show notebooks 13 | Then I can see a notebook in the terminal 14 | And the notebook status in the terminal is running 15 | 16 | Scenario: Stop notebook from the CLI 17 | Given I am connected to the app 18 | And a notebook is running 19 | When I execute lightning stop notebook 20 | Then I can see a notebook in the UI 21 | And the notebook status in the UI is stopped 22 | When I execute lightning show notebooks 23 | Then I can see a notebook in the terminal 24 | And the notebook status in the terminal is stopped 25 | 26 | Scenario: View notebooks from the CLI 27 | Given I am connected to the app 28 | And a notebook is running 29 | When I execute lightning show notebooks 30 | Then I can see a notebook in the terminal 31 | And the notebook status in the terminal is running 32 | 33 | Scenario: Stop and restart a notebook from the CLI 34 | Given I am connected to the app 35 | When I execute lightning run notebook 36 | Then I can see a notebook in the UI 37 | And the notebook status in the UI is running 38 | When I execute lightning stop notebook 39 | Then the notebook status in the UI is stopped 40 | When I execute lightning run notebook 41 | Then the notebook status in the UI is running 42 | And I can open the notebook 43 | -------------------------------------------------------------------------------- /tests/features/steps/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/tests/features/steps/__init__.py -------------------------------------------------------------------------------- /tests/features/steps/app.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | import sys 4 | 5 | from behave import given 6 | 7 | 8 | @given("I am connected to the app") 9 | def step_impl(context): 10 | cmd = [ 11 | sys.executable, 12 | "-m", 13 | "lightning", 14 | "connect", 15 | context.app_id, 16 | ] 17 | 18 | process = subprocess.Popen( 19 | cmd, 20 | env=os.environ.copy(), 21 | ) 22 | process.wait() 23 | -------------------------------------------------------------------------------- /tests/features/sweep.feature: -------------------------------------------------------------------------------- 1 | Feature: Sweeps 2 | As an app user, 3 | I want to start an experiment sweep on instance types of my choice, 4 | so that I can determine the best hyper-parameters for my model. 5 | 6 | Scenario: Start sweep from the CLI 7 | Given I am connected to the app 8 | When I execute lightning run sweep 9 | Then I can see a sweep in the UI 10 | And the sweep status in the UI is running 11 | And I can open the logger 12 | When I execute lightning show sweeps 13 | Then I can see a sweep in the terminal 14 | And the sweep status in the terminal is running 15 | 16 | Scenario: Stop sweep from the CLI 17 | Given I am connected to the app 18 | And a sweep is running 19 | When I execute lightning stop sweep 20 | Then I can see a sweep in the UI 21 | And the sweep status in the UI is stopped 22 | When I execute lightning show sweeps 23 | Then I can see a sweep in the terminal 24 | And the sweep status in the terminal is stopped 25 | 26 | Scenario: View sweeps from the CLI 27 | Given I am connected to the app 28 | And a sweep is running 29 | When I execute lightning show sweeps 30 | Then I can see a sweep in the terminal 31 | And the sweep status in the terminal is running 32 | -------------------------------------------------------------------------------- /tests/loggers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lightning-Universe/Training-Studio_app/c802c237a5de608fa17fec31577cc3302623231e/tests/loggers/__init__.py -------------------------------------------------------------------------------- /tests/loggers/test_streamlit.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from unittest.mock import MagicMock 3 | 4 | from lightning.app.utilities.state import AppState 5 | 6 | from lightning_training_studio.loggers.streamlit.hyperplot import HiPlotFlow, render_fn 7 | 8 | 9 | def test_hiplot(monkeypatch): 10 | hiplot = MagicMock() 11 | monkeypatch.setitem(sys.modules, "hiplot", hiplot) 12 | 13 | flow = HiPlotFlow() 14 | state = AppState() 15 | state._state = flow.state 16 | render_fn(state) 17 | 18 | hiplot = MagicMock() 19 | hiplot.Experiment.from_iterable().to_streamlit().display.return_value = {} 20 | monkeypatch.setitem(sys.modules, "hiplot", hiplot) 21 | 22 | flow = HiPlotFlow() 23 | flow.data = [{"a": "1", "b": "2"}] 24 | state = AppState() 25 | state._state = flow.state 26 | render_fn(state) 27 | -------------------------------------------------------------------------------- /tests/loggers/test_tensorboard.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import MagicMock 2 | 3 | 4 | def test_tensorboard_logger(monkeypatch): 5 | from lightning_training_studio.loggers import tensorboard 6 | 7 | pytorch_lightning = MagicMock() 8 | monkeypatch.setattr(tensorboard, "pytorch_lightning", pytorch_lightning) 9 | logger = tensorboard.TensorboardLogger() 10 | 11 | def add_traced(cls, name, pre_fn=None): 12 | setattr(cls, "v" + name, pre_fn) 13 | 14 | tracer = MagicMock() 15 | tracer.add_traced = add_traced 16 | logger.configure_tracer(tracer, "a", 0, "a", {"x": 1}) 17 | _, _, kwargs = pytorch_lightning.Trainer.v__init__(MagicMock, (), {}) 18 | assert kwargs["logger"].__class__.__name__ == "TensorBoardLogger" 19 | -------------------------------------------------------------------------------- /tests/loggers/test_wandb.py: -------------------------------------------------------------------------------- 1 | import os 2 | from unittest.mock import MagicMock 3 | 4 | import pytest 5 | 6 | from lightning_training_studio.loggers import wandb as wandb_logger 7 | 8 | 9 | def test_wandb_logger(monkeypatch): 10 | wandb = MagicMock() 11 | pytorch_lightning = MagicMock() 12 | api = MagicMock() 13 | report = MagicMock() 14 | report.id = "c" 15 | api.create_report.return_value = report 16 | wandb.Api.return_value = api 17 | 18 | monkeypatch.setattr(wandb_logger, "wandb", wandb) 19 | monkeypatch.setattr(wandb_logger, "pytorch_lightning", pytorch_lightning) 20 | 21 | with pytest.raises(Exception, match="setting your API key or entity"): 22 | logger = wandb_logger.WandbLogger() 23 | 24 | monkeypatch.setattr(os, "environ", {"WANDB_API_KEY": "a", "WANDB_ENTITY": "b"}) 25 | logger = wandb_logger.WandbLogger() 26 | logger.on_after_experiment_start("a") 27 | assert report.title == "A Report" 28 | assert logger.report_url == "https://wandb.ai/b/a/reports/a--c" 29 | 30 | report.save.assert_called() 31 | logger.report.blocks = None 32 | logger.on_after_experiment_end("a", 0, "val_acc", 1, {"x": 1}) 33 | assert logger.report.blocks 34 | 35 | assert logger.configure_layout() == [ 36 | {"name": "Project", "content": "https://wandb.ai/b/a/reports/a"}, 37 | {"name": "Report", "content": "https://wandb.ai/b/a/reports/a--c"}, 38 | ] 39 | logger.connect(MagicMock()) 40 | assert logger.get_url(0) == "https://wandb.ai/b/a/reports/a--c" 41 | 42 | def add_traced(cls, name, pre_fn=None): 43 | setattr(cls, "v" + name, pre_fn) 44 | 45 | tracer = MagicMock() 46 | tracer.add_traced = add_traced 47 | logger.configure_tracer(tracer, "a", 0, "a", {"x": 1}) 48 | assert pytorch_lightning.Trainer.v__init__.__name__ == "trainer_pre_fn" 49 | -------------------------------------------------------------------------------- /tests/test_examples.py: -------------------------------------------------------------------------------- 1 | import os 2 | from functools import partial 3 | from unittest import mock 4 | 5 | from lightning.app.testing import application_testing, LightningTestApp 6 | 7 | 8 | class LightningHPOTestApp(LightningTestApp): 9 | def __init__(self, root, total_experiments=2, **kwargs): 10 | root.total_experiments = total_experiments 11 | super().__init__(root, **kwargs) 12 | 13 | def on_before_run_once(self): 14 | if self.root.total_experiments_done == self.root.total_experiments: 15 | return True 16 | 17 | 18 | @mock.patch.dict(os.environ, {"WANDB_ENTITY": "thomas-chaton"}) 19 | @mock.patch.dict(os.environ, {"WANDB_API_KEY": "eabe6ced59f74db139187745544572f81ef76162"}) 20 | def test_custom_objective_sweep_streamlit(): 21 | command_line = [ 22 | os.path.join(os.getcwd(), "sweep_examples/1_app_agnostic.py"), 23 | "--open-ui", 24 | "False", 25 | ] 26 | result = application_testing(LightningHPOTestApp, command_line) 27 | assert result.exit_code == 0, result.__dict__ 28 | 29 | 30 | @mock.patch.dict(os.environ, {"WANDB_ENTITY": "thomas-chaton"}) 31 | @mock.patch.dict(os.environ, {"WANDB_API_KEY": "eabe6ced59f74db139187745544572f81ef76162"}) 32 | def test_pytorch_lightning_objective_sweep_wandb(): 33 | command_line = [ 34 | os.path.join(os.getcwd(), "sweep_examples/2_app_pytorch_lightning.py"), 35 | "--open-ui", 36 | "False", 37 | ] 38 | result = application_testing(partial(LightningHPOTestApp, total_experiments=1), command_line) 39 | assert result.exit_code == 0, result.__dict__ 40 | 41 | 42 | def test_pytorch_lightning_custom_objective_sweep(): 43 | command_line = [ 44 | os.path.join(os.getcwd(), "sweep_examples/3_app_sklearn.py"), 45 | "--open-ui", 46 | "False", 47 | ] 48 | result = application_testing(partial(LightningHPOTestApp, total_experiments=1), command_line) 49 | assert result.exit_code == 0, result.__dict__ 50 | -------------------------------------------------------------------------------- /tests/utilities/test_utils.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import Column 2 | from sqlmodel import Field, SQLModel 3 | 4 | from lightning_training_studio.distributions import Uniform 5 | from lightning_training_studio.distributions.distributions import Categorical 6 | from lightning_training_studio.utilities.enum import Stage 7 | from lightning_training_studio.utilities.utils import get_best_model_path, get_best_model_score, pydantic_column_type 8 | from tests.helpers import MockObjective 9 | 10 | 11 | def test_score_and_path(): 12 | from lightning_training_studio.components.sweep import Sweep 13 | 14 | sweep = Sweep( 15 | 5, 16 | parallel_experiments=3, 17 | objective_cls=MockObjective, 18 | distributions={ 19 | "best_model_score": Uniform(0, 100), 20 | "best_model_path": Categorical(choices=["a", "b", "c", "d", "e", "f", "g"]), 21 | }, 22 | ) 23 | assert get_best_model_score(sweep) is None 24 | assert get_best_model_path(sweep) is None 25 | 26 | assert sweep.stage == Stage.NOT_STARTED 27 | 28 | sweep.run() 29 | assert sweep.stage == Stage.RUNNING 30 | assert len(sweep.experiments) == 3 31 | assert sweep.experiments[0]["stage"] == Stage.SUCCEEDED 32 | assert sweep.w_0.status.stage == Stage.STOPPED 33 | 34 | best_model_score = get_best_model_score(sweep) 35 | assert best_model_score == max([w.best_model_score for w in sweep.works()]) 36 | best_model_path = [w.best_model_path for w in sweep.works() if w.best_model_score == best_model_score][0] 37 | assert sweep.best_model_path == best_model_path 38 | 39 | sweep.run() 40 | assert len(sweep.experiments) == 5 41 | assert sweep.experiments[4]["stage"] == Stage.SUCCEEDED 42 | assert sweep.w_4.status.stage == Stage.STOPPED 43 | assert sweep.stage == Stage.RUNNING 44 | 45 | best_model_score = get_best_model_score(sweep) 46 | assert best_model_score == max([w.best_model_score for w in sweep.works()]) 47 | best_model_path = [w.best_model_path for w in sweep.works() if w.best_model_score == best_model_score][0] 48 | assert sweep.best_model_path == best_model_path 49 | 50 | sweep.run() 51 | assert sweep.stage == Stage.SUCCEEDED 52 | 53 | 54 | def test_pydantic_column_type(): 55 | class NestedModel(SQLModel): 56 | name: str 57 | 58 | class Model(SQLModel): 59 | name: str 60 | nested_model: NestedModel = Field(..., sa_column=Column(pydantic_column_type(NestedModel))) 61 | 62 | model = Model(name="a", nested_model=NestedModel(name="b")) 63 | str_repr = model.json() 64 | new_model = Model.parse_raw(str_repr) 65 | assert isinstance(new_model.nested_model, NestedModel) 66 | --------------------------------------------------------------------------------