Skip to content

Init: Models store API #15811

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 51 commits into from
Jan 27, 2023
Merged
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
17d2ac5
placeholder
Borda Nov 24, 2022
505f6b1
porting code
Borda Dec 13, 2022
3a820d7
move > lai
Borda Dec 30, 2022
9847557
cleaning
Borda Jan 20, 2023
701e240
readme
Borda Jan 20, 2023
a259966
precommit
Borda Jan 20, 2023
074c337
store
Borda Jan 20, 2023
a086d85
docs
Borda Jan 20, 2023
a411488
ci
Borda Jan 20, 2023
daad294
azure
Borda Jan 20, 2023
8dec395
latest
Borda Jan 20, 2023
0e22d6c
py3.9
Borda Jan 20, 2023
112c6b9
dir
Borda Jan 20, 2023
e1268f3
_
Borda Jan 20, 2023
b910df4
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 20, 2023
03781df
tests
Borda Jan 20, 2023
fcefc30
Merge branch 'feat/model2cloud' of https://github.com/PyTorchLightnin…
Borda Jan 20, 2023
86d5820
imports
Borda Jan 20, 2023
4938a8d
imports
Borda Jan 20, 2023
29e41d1
cleaning
Borda Jan 20, 2023
e157483
env
Borda Jan 20, 2023
010edd0
exceptions
Borda Jan 20, 2023
3283ef9
another pass
Borda Jan 20, 2023
8d873d1
error
Borda Jan 20, 2023
a8308df
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 20, 2023
741b33b
assert
Borda Jan 20, 2023
84c1591
paths
Borda Jan 20, 2023
3d8e35f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 20, 2023
1f003b8
debug
Borda Jan 24, 2023
6782769
if
Borda Jan 25, 2023
a1f2567
move CONSTANTs
Borda Jan 25, 2023
94c90ad
imports
Borda Jan 25, 2023
acc2b6e
drop test dev
Borda Jan 25, 2023
274abdc
ci
Borda Jan 25, 2023
8af21a2
Merge branch 'master' into feat/model2cloud
Borda Jan 25, 2023
eff305d
reuse constants
Borda Jan 25, 2023
dd4a6ea
Merge branch 'feat/model2cloud' of https://github.com/PyTorchLightnin…
Borda Jan 25, 2023
3fa82b0
cleaning
Borda Jan 25, 2023
193a7da
Merge branch 'master' into feat/model2cloud
Borda Jan 25, 2023
955b6b8
Merge branch 'master' into feat/model2cloud
Borda Jan 26, 2023
ef366ad
explicit
Borda Jan 26, 2023
003b25c
todo
Borda Jan 26, 2023
4cef07c
Merge branch 'master' into feat/model2cloud
Borda Jan 26, 2023
318036f
Apply suggestions from code review
Borda Jan 26, 2023
01e3e30
protected
Borda Jan 26, 2023
8f5aa05
Merge branch 'master' into feat/model2cloud
Borda Jan 26, 2023
c5dce15
fix
Borda Jan 26, 2023
017f271
renaming
Borda Jan 26, 2023
5e1f7c6
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 26, 2023
a4ab167
Merge branch 'master' into feat/model2cloud
Borda Jan 26, 2023
33986c0
Merge branch 'master' into feat/model2cloud
Borda Jan 27, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .azure/app-cloud-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ jobs:
workspace:
clean: all
variables:
FREEZE_REQUIREMENTS: "1"
HEADLESS: '1'
PACKAGE_LIGHTNING: '1'
CLOUD: '1'
Expand Down Expand Up @@ -145,8 +146,6 @@ jobs:
- bash: |
pip install -e .[test] \
-f https://download.pytorch.org/whl/cpu/torch_stable.html
env:
FREEZE_REQUIREMENTS: "1"
displayName: 'Install Lightning & dependencies'

- bash: |
Expand Down
67 changes: 67 additions & 0 deletions .azure/app-cloud-store.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Python package
# Create and test a Python package on multiple Python versions.
# Add steps that analyze code, save the dist with the build record, publish to a PyPI-compatible index, and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/python

trigger:
tags:
include:
- '*'
branches:
include:
- "master"
- "release/*"
- "refs/tags/*"

pr:
branches:
include:
- "master"
- "release/*"
paths:
include:
- ".actions/**"
- ".azure/app-cloud-store.yml"
- "src/lightning/store/**"
- "tests/tests_cloud/**"
- "setup.py"
exclude:
- "*.md"
- "**/*.md"

jobs:
- job: test_store
pool:
vmImage: $(imageName)
strategy:
matrix:
Linux:
imageName: 'ubuntu-latest'
Mac:
imageName: 'macOS-latest'
Windows:
imageName: 'windows-latest'
timeoutInMinutes: "20"
cancelTimeoutInMinutes: "1"
workspace:
clean: all
variables:
FREEZE_REQUIREMENTS: "1"
TORCH_URL: "https://download.pytorch.org/whl/cpu/torch_stable.html"
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.9'

- bash: pip install -e .[test] -f $(TORCH_URL)
displayName: 'Install Lightning & dependencies'

- bash: |
python -m pytest -m "not cloud" tests_cloud --timeout=300 -v
workingDirectory: tests/
env:
API_KEY: $(LIGHTNING_API_KEY_PROD)
API_USERNAME: $(LIGHTNING_USERNAME_PROD)
PROJECT_ID: $(LIGHTNING_PROJECT_ID_PROD)
LIGHTNING_CLOUD_URL: $(LIGHTNING_CLOUD_URL_PROD)
displayName: 'Run the tests'
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,10 @@ wheels/
*.egg-info/
.installed.cfg
*.egg
src/lightning/*/
src/*/version.info
src/lightning/app/
src/lightning/fabric/
src/lightning/pytorch/

# PyInstaller
# Usually these files are written by a python script from a template
Expand Down
81 changes: 81 additions & 0 deletions src/lightning/store/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
## Getting Started

- Login to lightning.ai (_optional_) \<-- takes less than a minute. ⏩
- Store your models on the cloud \<-- simple call: `to_lightning_cloud(...)`. 🗳️
- Share it with your friends \<-- just share the "username/model_name" (and version if required) format. :handshake:
- They download using a simple call: `download_from_lightning_cloud("username/model_name", version="your_version")`. :wink:
- They load your cool model. `load_from_lightning_cloud("username/model_name", version="your_version")`. :tada:
- Lightning :zap: fast, isn't it?. :heart:

## Usage

**Storing to the cloud**

```python
from lightning.store import to_lightning_cloud
from sample.model import LitAutoEncoder, Encoder, Decoder

# Initialize your model here
autoencoder = LitAutoEncoder(Encoder(), Decoder())

# Pass the model object:
# No need to pass the username (we'll deduce ourselves), just pass the model name you want as the first argument (with an optional version):
# format: `model_name:version` (version can either be latest or combination of digits and full-stops: 1.0.0 for example)
to_lightning_cloud("unique_model_mnist", model=autoencoder, source_code_path="sample")

# version:
to_lightning_cloud(
"unique_model_mnist",
version="1.0.0",
model=autoencoder,
source_code_path="sample/model.py",
)

# OR: (this will save the file which has the model defined)
to_lightning_cloud("krshrimali/unique_model_mnist", model=autoencoder)
```

You can also pass the checkpoint path: `to_lightning_cloud("model_name", version="latest", checkpoint_path=...)`.

**Downloading from the cloud**

```python
from lightning.store import download_from_lightning_cloud

download_from_lightning_cloud("krshrimali/unique_model_mnist", output_dir="your_output_dir")
# OR: (default to lightning_model_storage $HOME/.lightning/lightning_model_store/username/<model_name>/version_<version_with_dots_replaced_by_underscores>/ folder)
download_from_lightning_cloud("krshrimali/unique_model_mnist")
```

**Loading model**

```python
from lightning.store import load_from_lightning_cloud

# from <username>.<model_name>.version_<version_with_dots_replaced_by_underscores>.<model_source_file> import LitAutoEncoder, Encoder, Decoder
model = load_from_lightning_cloud(
"<username>/<model_name>>", version="version"
) # version is optional (defaults to latest)

# OR: load weights or checkpoint (if they were uploaded)
load_from_lightning_cloud(
"<username>/<model_name>", version="version", load_weights=True / False, load_checkpoint=True / False
)
print(model)
```

**Loading model weights**

```python
from lightning.store import load_from_lightning_cloud

# If you had passed an `output_dir=...` to download_from_lightning_cloud(...), then you can just do:
# from output_dir.<model_source_file> import LitAutoEncoder, Encoder, Decoder

model = LitAutoEncoder(Encoder(), Decoder())

model = load_from_lightning_cloud(load_weights=True, model=model)
print("State dict: ", model.state_dict())
```

Loading checkpoint is similar, just do: `load_checkpoint=True`.
3 changes: 3 additions & 0 deletions src/lightning/store/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from lightning.store.cloud_api import download_from_lightning_cloud, load_from_lightning_cloud, to_lightning_cloud

__all__ = ["download_from_lightning_cloud", "load_from_lightning_cloud", "to_lightning_cloud"]
62 changes: 62 additions & 0 deletions src/lightning/store/authentication.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Copyright The Lightning team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import json
import webbrowser

import requests
from requests.models import HTTPBasicAuth

from lightning.app.core.constants import get_lightning_cloud_url
from lightning.app.utilities.network import LightningClient

_LIGHTNING_CLOUD_URL = get_lightning_cloud_url()


def get_user_details():
client = LightningClient()
user_details = client.auth_service_get_user()
return user_details.username, user_details.api_key


def get_username_from_api_key(api_key: str):
response = requests.get(url=f"{_LIGHTNING_CLOUD_URL}/v1/auth/user", auth=HTTPBasicAuth("lightning", api_key))
if response.status_code != 200:
raise ConnectionRefusedError(
"API_KEY provided is either invalid or wasn't found in the database."
" Please ensure that you passed the correct API_KEY."
)
return json.loads(response.content)["username"]


def _check_browser_runnable():
try:
webbrowser.get()
except webbrowser.Error:
return False
return True


def authenticate(inp_api_key: str = ""):
if not inp_api_key:
if not _check_browser_runnable():
raise ValueError(
"Couldn't find a runnable browser in the current system/server."
" In order to run the commands on this system, we suggest passing the `api_key`"
" after logging into https://lightning.ai."
)
username, inp_api_key = get_user_details()
else:
username = get_username_from_api_key(inp_api_key)
return username, inp_api_key
Loading