├── tests ├── __init__.py ├── requirements.txt └── test_classifier.py ├── project ├── __init__.py ├── lit_autoencoder.py ├── lit_mnist.py └── lit_image_classifier.py ├── requirements.txt ├── setup.py ├── setup.cfg ├── .gitignore ├── .github └── workflows │ └── ci-testing.yml ├── README.md └── LICENSE /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /project/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pytorch-lightning >= 1.0.0rc2 2 | torch >= 1.3.0 3 | torchvision >= 0.6.0 4 | -------------------------------------------------------------------------------- /tests/requirements.txt: -------------------------------------------------------------------------------- 1 | coverage 2 | codecov>=2.1 3 | pytest>=3.0.5 4 | pytest-cov 5 | pytest-flake8 6 | flake8 7 | check-manifest 8 | twine==1.13.0 -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from setuptools import setup, find_packages 4 | 5 | setup( 6 | name='project', 7 | version='0.0.0', 8 | description='Describe Your Cool Project', 9 | author='', 10 | author_email='', 11 | # REPLACE WITH YOUR OWN GITHUB PROJECT LINK 12 | url='https://github.com/PyTorchLightning/pytorch-lightning-conference-seed', 13 | install_requires=['pytorch-lightning'], 14 | packages=find_packages(), 15 | ) 16 | 17 | -------------------------------------------------------------------------------- /tests/test_classifier.py: -------------------------------------------------------------------------------- 1 | from pytorch_lightning import Trainer, seed_everything 2 | from project.lit_mnist import LitClassifier 3 | from project.datasets.mnist import mnist 4 | 5 | 6 | def test_lit_classifier(): 7 | seed_everything(1234) 8 | 9 | model = LitClassifier() 10 | train, val, test = mnist() 11 | trainer = Trainer(limit_train_batches=50, limit_val_batches=20, max_epochs=2) 12 | trainer.fit(model, train, val) 13 | 14 | results = trainer.test(test_dataloaders=test) 15 | assert results[0]['test_acc'] > 0.7 16 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [tool:pytest] 2 | norecursedirs = 3 | .git 4 | dist 5 | build 6 | addopts = 7 | --strict 8 | --doctest-modules 9 | --durations=0 10 | 11 | [coverage:report] 12 | exclude_lines = 13 | pragma: no-cover 14 | pass 15 | 16 | [flake8] 17 | max-line-length = 120 18 | exclude = .tox,*.egg,build,temp 19 | select = E,W,F 20 | doctests = True 21 | verbose = 2 22 | # https://pep8.readthedocs.io/en/latest/intro.html#error-codes 23 | format = pylint 24 | # see: https://www.flake8rules.com/ 25 | ignore = 26 | E731 # Do not assign a lambda expression, use a def 27 | W504 # Line break occurred after a binary operator 28 | F401 # Module imported but unused 29 | F841 # Local variable name is assigned to but never used 30 | W605 # Invalid escape sequence 'x' 31 | 32 | # setup.cfg or tox.ini 33 | [check-manifest] 34 | ignore = 35 | *.yml 36 | .github 37 | .github/* 38 | 39 | [metadata] 40 | license_file = LICENSE 41 | description-file = README.md 42 | # long_description = file:README.md 43 | # long_description_content_type = text/markdown 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | .github 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # Lightning /research 30 | test_tube_exp/ 31 | tests/tests_tt_dir/ 32 | tests/save_dir 33 | default/ 34 | data/ 35 | test_tube_logs/ 36 | test_tube_data/ 37 | datasets/ 38 | model_weights/ 39 | tests/save_dir 40 | tests/tests_tt_dir/ 41 | processed/ 42 | raw/ 43 | 44 | # PyInstaller 45 | # Usually these files are written by a python script from a template 46 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 47 | *.manifest 48 | *.spec 49 | 50 | # Installer logs 51 | pip-log.txt 52 | pip-delete-this-directory.txt 53 | 54 | # Unit test / coverage reports 55 | htmlcov/ 56 | .tox/ 57 | .coverage 58 | .coverage.* 59 | .cache 60 | nosetests.xml 61 | coverage.xml 62 | *.cover 63 | .hypothesis/ 64 | .pytest_cache/ 65 | 66 | # Translations 67 | *.mo 68 | *.pot 69 | 70 | # Django stuff: 71 | *.log 72 | local_settings.py 73 | db.sqlite3 74 | 75 | # Flask stuff: 76 | instance/ 77 | .webassets-cache 78 | 79 | # Scrapy stuff: 80 | .scrapy 81 | 82 | # Sphinx documentation 83 | docs/_build/ 84 | 85 | # PyBuilder 86 | target/ 87 | 88 | # Jupyter Notebook 89 | .ipynb_checkpoints 90 | 91 | # pyenv 92 | .python-version 93 | 94 | # celery beat schedule file 95 | celerybeat-schedule 96 | 97 | # SageMath parsed files 98 | *.sage.py 99 | 100 | # Environments 101 | .env 102 | .venv 103 | env/ 104 | venv/ 105 | ENV/ 106 | env.bak/ 107 | venv.bak/ 108 | 109 | # Spyder project settings 110 | .spyderproject 111 | .spyproject 112 | 113 | # Rope project settings 114 | .ropeproject 115 | 116 | # mkdocs documentation 117 | /site 118 | 119 | # mypy 120 | .mypy_cache/ 121 | 122 | # IDEs 123 | .idea 124 | .vscode 125 | 126 | # seed project 127 | lightning_logs/ 128 | MNIST 129 | .DS_Store 130 | -------------------------------------------------------------------------------- /.github/workflows/ci-testing.yml: -------------------------------------------------------------------------------- 1 | name: CI testing 2 | 3 | # see: https://help.github.com/en/actions/reference/events-that-trigger-workflows 4 | on: 5 | # Trigger the workflow on push or pull request, but only for the master branch 6 | push: 7 | branches: 8 | - master 9 | pull_request: 10 | branches: 11 | - master 12 | 13 | jobs: 14 | pytest: 15 | 16 | runs-on: ${{ matrix.os }} 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | os: [ubuntu-20.04, macOS-10.15, windows-2019] 21 | python-version: [3.7] 22 | 23 | # Timeout: https://stackoverflow.com/a/59076067/4521646 24 | timeout-minutes: 35 25 | 26 | steps: 27 | - uses: actions/checkout@v2 28 | - name: Set up Python ${{ matrix.python-version }} 29 | uses: actions/setup-python@v2 30 | with: 31 | python-version: ${{ matrix.python-version }} 32 | 33 | # Github Actions: Run step on specific OS: https://stackoverflow.com/a/57948488/4521646 34 | - name: Setup macOS 35 | if: runner.os == 'macOS' 36 | run: | 37 | brew install libomp # https://github.com/pytorch/pytorch/issues/20030 38 | 39 | # Note: This uses an internal pip API and may not always work 40 | # https://github.com/actions/cache/blob/master/examples.md#multiple-oss-in-a-workflow 41 | - name: Get pip cache 42 | id: pip-cache 43 | run: | 44 | python -c "from pip._internal.locations import USER_CACHE_DIR; print('::set-output name=dir::' + USER_CACHE_DIR)" 45 | 46 | - name: Cache pip 47 | uses: actions/cache@v2 48 | with: 49 | path: ${{ steps.pip-cache.outputs.dir }} 50 | key: ${{ runner.os }}-py${{ matrix.python-version }}-${{ hashFiles('requirements.txt') }} 51 | restore-keys: | 52 | ${{ runner.os }}-py${{ matrix.python-version }}- 53 | 54 | - name: Install dependencies 55 | run: | 56 | pip install --requirement requirements.txt --upgrade --quiet --find-links https://download.pytorch.org/whl/cpu/torch_stable.html --use-feature=2020-resolver 57 | pip install --requirement tests/requirements.txt --quiet --use-feature=2020-resolver 58 | python --version 59 | pip --version 60 | pip list 61 | shell: bash 62 | 63 | - name: Tests 64 | run: | 65 | coverage run --source project -m py.test project tests -v --junitxml=junit/test-results-${{ runner.os }}-${{ matrix.python-version }}.xml 66 | 67 | - name: Statistics 68 | if: success() 69 | run: | 70 | coverage report 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Deep learning project seed 2 | Use this seed to start new deep learning / ML projects. 3 | 4 | - Built in setup.py 5 | - Built in requirements 6 | - Examples with MNIST 7 | - Badges 8 | - Bibtex 9 | 10 | #### Goals 11 | The goal of this seed is to structure ML paper-code the same so that work can easily be extended and replicated. 12 | 13 | ### DELETE EVERYTHING ABOVE FOR YOUR PROJECT 14 | 15 | --- 16 | 17 |
18 | 19 | # Your Project Name 20 | 21 | [![Paper](http://img.shields.io/badge/paper-arxiv.1001.2234-B31B1B.svg)](https://www.nature.com/articles/nature14539) 22 | [![Conference](http://img.shields.io/badge/NeurIPS-2019-4b44ce.svg)](https://papers.nips.cc/book/advances-in-neural-information-processing-systems-31-2018) 23 | [![Conference](http://img.shields.io/badge/ICLR-2019-4b44ce.svg)](https://papers.nips.cc/book/advances-in-neural-information-processing-systems-31-2018) 24 | [![Conference](http://img.shields.io/badge/AnyConference-year-4b44ce.svg)](https://papers.nips.cc/book/advances-in-neural-information-processing-systems-31-2018) 25 | 29 | ![CI testing](https://github.com/PyTorchLightning/deep-learning-project-template/workflows/CI%20testing/badge.svg?branch=master&event=push) 30 | 31 | 32 | 35 |
36 | 37 | ## Description 38 | What it does 39 | 40 | ## How to run 41 | First, install dependencies 42 | ```bash 43 | # clone project 44 | git clone https://github.com/YourGithubName/deep-learning-project-template 45 | 46 | # install project 47 | cd deep-learning-project-template 48 | pip install -e . 49 | pip install -r requirements.txt 50 | ``` 51 | Next, navigate to any file and run it. 52 | ```bash 53 | # module folder 54 | cd project 55 | 56 | # run module (example: mnist as your main contribution) 57 | python lit_classifier_main.py 58 | ``` 59 | 60 | ## Imports 61 | This project is setup as a package which means you can now easily import any file into any other file like so: 62 | ```python 63 | from project.datasets.mnist import mnist 64 | from project.lit_classifier_main import LitClassifier 65 | from pytorch_lightning import Trainer 66 | 67 | # model 68 | model = LitClassifier() 69 | 70 | # data 71 | train, val, test = mnist() 72 | 73 | # train 74 | trainer = Trainer() 75 | trainer.fit(model, train, val) 76 | 77 | # test using the best model! 78 | trainer.test(test_dataloaders=test) 79 | ``` 80 | 81 | ### Citation 82 | ``` 83 | @article{YourName, 84 | title={Your Title}, 85 | author={Your team}, 86 | journal={Location}, 87 | year={Year} 88 | } 89 | ``` 90 | -------------------------------------------------------------------------------- /project/lit_autoencoder.py: -------------------------------------------------------------------------------- 1 | from argparse import ArgumentParser 2 | import torch 3 | from torch import nn 4 | import torch.nn.functional as F 5 | from torch.utils.data import DataLoader 6 | import pytorch_lightning as pl 7 | from torch.utils.data import random_split 8 | 9 | from torchvision.datasets.mnist import MNIST 10 | from torchvision import transforms 11 | 12 | 13 | class LitAutoEncoder(pl.LightningModule): 14 | 15 | def __init__(self): 16 | super().__init__() 17 | self.encoder = nn.Sequential( 18 | nn.Linear(28 * 28, 64), 19 | nn.ReLU(), 20 | nn.Linear(64, 3) 21 | ) 22 | self.decoder = nn.Sequential( 23 | nn.Linear(3, 64), 24 | nn.ReLU(), 25 | nn.Linear(64, 28 * 28) 26 | ) 27 | 28 | def forward(self, x): 29 | # in lightning, forward defines the prediction/inference actions 30 | embedding = self.encoder(x) 31 | return embedding 32 | 33 | def training_step(self, batch, batch_idx): 34 | x, y = batch 35 | x = x.view(x.size(0), -1) 36 | z = self.encoder(x) 37 | x_hat = self.decoder(z) 38 | loss = F.mse_loss(x_hat, x) 39 | return loss 40 | 41 | def configure_optimizers(self): 42 | optimizer = torch.optim.Adam(self.parameters(), lr=1e-3) 43 | return optimizer 44 | 45 | 46 | def cli_main(): 47 | pl.seed_everything(1234) 48 | 49 | # ------------ 50 | # args 51 | # ------------ 52 | parser = ArgumentParser() 53 | parser.add_argument('--batch_size', default=32, type=int) 54 | parser.add_argument('--hidden_dim', type=int, default=128) 55 | parser = pl.Trainer.add_argparse_args(parser) 56 | args = parser.parse_args() 57 | 58 | # ------------ 59 | # data 60 | # ------------ 61 | dataset = MNIST('', train=True, download=True, transform=transforms.ToTensor()) 62 | mnist_test = MNIST('', train=False, download=True, transform=transforms.ToTensor()) 63 | mnist_train, mnist_val = random_split(dataset, [55000, 5000]) 64 | 65 | train_loader = DataLoader(mnist_train, batch_size=args.batch_size) 66 | val_loader = DataLoader(mnist_val, batch_size=args.batch_size) 67 | test_loader = DataLoader(mnist_test, batch_size=args.batch_size) 68 | 69 | # ------------ 70 | # model 71 | # ------------ 72 | model = LitAutoEncoder() 73 | 74 | # ------------ 75 | # training 76 | # ------------ 77 | trainer = pl.Trainer.from_argparse_args(args) 78 | trainer.fit(model, train_loader, val_loader) 79 | 80 | # ------------ 81 | # testing 82 | # ------------ 83 | result = trainer.test(test_dataloaders=test_loader) 84 | print(result) 85 | 86 | 87 | if __name__ == '__main__': 88 | cli_main() 89 | -------------------------------------------------------------------------------- /project/lit_mnist.py: -------------------------------------------------------------------------------- 1 | from argparse import ArgumentParser 2 | 3 | import torch 4 | import pytorch_lightning as pl 5 | from torch.nn import functional as F 6 | from torch.utils.data import DataLoader, random_split 7 | 8 | from torchvision.datasets.mnist import MNIST 9 | from torchvision import transforms 10 | 11 | 12 | class LitClassifier(pl.LightningModule): 13 | def __init__(self, hidden_dim=128, learning_rate=1e-3): 14 | super().__init__() 15 | self.save_hyperparameters() 16 | 17 | self.l1 = torch.nn.Linear(28 * 28, self.hparams.hidden_dim) 18 | self.l2 = torch.nn.Linear(self.hparams.hidden_dim, 10) 19 | 20 | def forward(self, x): 21 | x = x.view(x.size(0), -1) 22 | x = torch.relu(self.l1(x)) 23 | x = torch.relu(self.l2(x)) 24 | return x 25 | 26 | def training_step(self, batch, batch_idx): 27 | x, y = batch 28 | y_hat = self(x) 29 | loss = F.cross_entropy(y_hat, y) 30 | return loss 31 | 32 | def validation_step(self, batch, batch_idx): 33 | x, y = batch 34 | y_hat = self(x) 35 | loss = F.cross_entropy(y_hat, y) 36 | self.log('valid_loss', loss) 37 | 38 | def test_step(self, batch, batch_idx): 39 | x, y = batch 40 | y_hat = self(x) 41 | loss = F.cross_entropy(y_hat, y) 42 | self.log('test_loss', loss) 43 | 44 | def configure_optimizers(self): 45 | return torch.optim.Adam(self.parameters(), lr=self.hparams.learning_rate) 46 | 47 | @staticmethod 48 | def add_model_specific_args(parent_parser): 49 | parser = ArgumentParser(parents=[parent_parser], add_help=False) 50 | parser.add_argument('--hidden_dim', type=int, default=128) 51 | parser.add_argument('--learning_rate', type=float, default=0.0001) 52 | return parser 53 | 54 | 55 | def cli_main(): 56 | pl.seed_everything(1234) 57 | 58 | # ------------ 59 | # args 60 | # ------------ 61 | parser = ArgumentParser() 62 | parser.add_argument('--batch_size', default=32, type=int) 63 | parser = pl.Trainer.add_argparse_args(parser) 64 | parser = LitClassifier.add_model_specific_args(parser) 65 | args = parser.parse_args() 66 | 67 | # ------------ 68 | # data 69 | # ------------ 70 | dataset = MNIST('', train=True, download=True, transform=transforms.ToTensor()) 71 | mnist_test = MNIST('', train=False, download=True, transform=transforms.ToTensor()) 72 | mnist_train, mnist_val = random_split(dataset, [55000, 5000]) 73 | 74 | train_loader = DataLoader(mnist_train, batch_size=args.batch_size) 75 | val_loader = DataLoader(mnist_val, batch_size=args.batch_size) 76 | test_loader = DataLoader(mnist_test, batch_size=args.batch_size) 77 | 78 | # ------------ 79 | # model 80 | # ------------ 81 | model = LitClassifier(args.hidden_dim, args.learning_rate) 82 | 83 | # ------------ 84 | # training 85 | # ------------ 86 | trainer = pl.Trainer.from_argparse_args(args) 87 | trainer.fit(model, train_loader, val_loader) 88 | 89 | # ------------ 90 | # testing 91 | # ------------ 92 | trainer.test(test_dataloaders=test_loader) 93 | 94 | 95 | if __name__ == '__main__': 96 | cli_main() 97 | -------------------------------------------------------------------------------- /project/lit_image_classifier.py: -------------------------------------------------------------------------------- 1 | from argparse import ArgumentParser 2 | 3 | import torch 4 | import pytorch_lightning as pl 5 | from torch.nn import functional as F 6 | from torch.utils.data import DataLoader, random_split 7 | 8 | from torchvision.datasets.mnist import MNIST 9 | from torchvision import transforms 10 | 11 | 12 | class Backbone(torch.nn.Module): 13 | def __init__(self, hidden_dim=128): 14 | super().__init__() 15 | self.l1 = torch.nn.Linear(28 * 28, hidden_dim) 16 | self.l2 = torch.nn.Linear(hidden_dim, 10) 17 | 18 | def forward(self, x): 19 | x = x.view(x.size(0), -1) 20 | x = torch.relu(self.l1(x)) 21 | x = torch.relu(self.l2(x)) 22 | return x 23 | 24 | 25 | class LitClassifier(pl.LightningModule): 26 | def __init__(self, backbone, learning_rate=1e-3): 27 | super().__init__() 28 | self.save_hyperparameters() 29 | self.backbone = backbone 30 | 31 | def forward(self, x): 32 | # use forward for inference/predictions 33 | embedding = self.backbone(x) 34 | return embedding 35 | 36 | def training_step(self, batch, batch_idx): 37 | x, y = batch 38 | y_hat = self.backbone(x) 39 | loss = F.cross_entropy(y_hat, y) 40 | self.log('train_loss', loss, on_epoch=True) 41 | return loss 42 | 43 | def validation_step(self, batch, batch_idx): 44 | x, y = batch 45 | y_hat = self.backbone(x) 46 | loss = F.cross_entropy(y_hat, y) 47 | self.log('valid_loss', loss, on_step=True) 48 | 49 | def test_step(self, batch, batch_idx): 50 | x, y = batch 51 | y_hat = self.backbone(x) 52 | loss = F.cross_entropy(y_hat, y) 53 | self.log('test_loss', loss) 54 | 55 | def configure_optimizers(self): 56 | # self.hparams available because we called self.save_hyperparameters() 57 | return torch.optim.Adam(self.parameters(), lr=self.hparams.learning_rate) 58 | 59 | @staticmethod 60 | def add_model_specific_args(parent_parser): 61 | parser = ArgumentParser(parents=[parent_parser], add_help=False) 62 | parser.add_argument('--learning_rate', type=float, default=0.0001) 63 | return parser 64 | 65 | 66 | def cli_main(): 67 | pl.seed_everything(1234) 68 | 69 | # ------------ 70 | # args 71 | # ------------ 72 | parser = ArgumentParser() 73 | parser.add_argument('--batch_size', default=32, type=int) 74 | parser.add_argument('--hidden_dim', type=int, default=128) 75 | parser = pl.Trainer.add_argparse_args(parser) 76 | parser = LitClassifier.add_model_specific_args(parser) 77 | args = parser.parse_args() 78 | 79 | # ------------ 80 | # data 81 | # ------------ 82 | dataset = MNIST('', train=True, download=True, transform=transforms.ToTensor()) 83 | mnist_test = MNIST('', train=False, download=True, transform=transforms.ToTensor()) 84 | mnist_train, mnist_val = random_split(dataset, [55000, 5000]) 85 | 86 | train_loader = DataLoader(mnist_train, batch_size=args.batch_size) 87 | val_loader = DataLoader(mnist_val, batch_size=args.batch_size) 88 | test_loader = DataLoader(mnist_test, batch_size=args.batch_size) 89 | 90 | # ------------ 91 | # model 92 | # ------------ 93 | model = LitClassifier(Backbone(hidden_dim=args.hidden_dim), args.learning_rate) 94 | 95 | # ------------ 96 | # training 97 | # ------------ 98 | trainer = pl.Trainer.from_argparse_args(args) 99 | trainer.fit(model, train_loader, val_loader) 100 | 101 | # ------------ 102 | # testing 103 | # ------------ 104 | result = trainer.test(test_dataloaders=test_loader) 105 | print(result) 106 | 107 | 108 | if __name__ == '__main__': 109 | cli_main() 110 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------