Skip to content

Commit 8abec25

Browse files
Contributing guidelines (#1125)
Signed-off-by: Mingxin Zheng <18563433+mingxin-zheng@users.noreply.github.com> Fixes #1119 . ### Description Provide guidelines for tutorial contributions ### Checks <!--- Put an `x` in all the boxes that apply, and remove the not applicable items --> - [x] Notebook runs automatically `./runner [-p <regex_pattern>]` Signed-off-by: Mingxin Zheng <18563433+mingxin-zheng@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 5883235 commit 8abec25

File tree

7 files changed

+577
-7
lines changed

7 files changed

+577
-7
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Template for new MONAI notebook tutorials
2+
3+
- [Jupyter notebook template](example_feature.ipynb)
4+
- [Python script template](example_class.py)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Copyright (c) MONAI Consortium
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
# Unless required by applicable law or agreed to in writing, software
7+
# distributed under the License is distributed on an "AS IS" BASIS,
8+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9+
# See the License for the specific language governing permissions and
10+
# limitations under the License.
11+
12+
import os
13+
from glob import glob
14+
15+
import numpy as np
16+
from monai.data import create_test_image_2d
17+
from PIL import Image
18+
19+
20+
class ExampleImageGenerator():
21+
def __init__(self, num_image=40, image_size=(128, 128)):
22+
self.num_image = num_image
23+
self.image_size = image_size
24+
25+
def generate(self, tempdir):
26+
for i in range(self.num_image):
27+
im, seg = create_test_image_2d(
28+
self.image_size[0], self.image_size[1], num_seg_classes=1,random_state=np.random.RandomState(42)
29+
)
30+
Image.fromarray((im * 255).astype("uint8")).save(os.path.join(tempdir, f"img{i:d}.png"))
31+
Image.fromarray((seg * 255).astype("uint8")).save(os.path.join(tempdir, f"seg{i:d}.png"))
32+
33+
images = sorted(glob(os.path.join(tempdir, "img*.png")))
34+
segs = sorted(glob(os.path.join(tempdir, "seg*.png")))
35+
return (images, seg)

.github/contributing_templates/notebook/example_feature.ipynb

Lines changed: 242 additions & 0 deletions
Large diffs are not rendered by default.

.github/pull_request_template.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,8 @@ A few sentences describing the changes proposed in this pull request.
55

66
### Checks
77
<!--- Put an `x` in all the boxes that apply, and remove the not applicable items -->
8-
- [ ] Notebook runs automatically `./runner [-p <regex_pattern>]`
8+
- [ ] Avoid including large-size files in the PR.
9+
- [ ] Clean up long text outputs from code cells in the notebook.
10+
- [ ] Remove private info such as user name and private key from the notebook and script files.
11+
- [ ] Ensure (1) hyperlinks and markdown anchors are working (2) use relative paths for tutorial repo files (3) put figure and graphs in the `./figure` folder
12+
- [ ] Notebook runs automatically `./runner.sh -t <path to .ipynb file>`

CONTRIBUTING.md

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
- [Introduction](#introduction)
2+
- [The contribution process](#the-contribution-process)
3+
- [Raise an issue](#raise-an-issue)
4+
- [Create a fork](#create-a-fork)
5+
- [Create a new folder](#create-a-new-folder)
6+
- [Add license](#add-license)
7+
- [Create a notebook](#create-a-notebook)
8+
- [Commit new changes](#commit-new-changes)
9+
- [Open a pull request](#open-a-pull-request)
10+
- [Common recommendations for the review](#common-recommendations-for-the-review)
11+
- [CI/CD test passing guide](#cicd-test-passing-guide)
12+
- [PEP 8 Style](#pep-8-style)
13+
- [Notebook execution](#notebook-execution)
14+
- [Format requirements](#format-requirements)
15+
- [Benchmarking result report](#benchmarking-result-report)
16+
17+
## Introduction
18+
19+
Thank you for considering a contribution to the MONAI Tutorials Repository and reading the Contributing Guidelines.
20+
21+
The following is a set of guidelines for contributing tutorials to Project MONAI.
22+
We want the guidelines to support the growth of the project, instead of restricting the depth and breadth of your contribution.
23+
If you have any questions about the guideline, please communicate with us and we are happy to discuss them with you.
24+
MONAI is an open-source project and its success relies on the entire community.
25+
26+
Please feel free to propose changes to this document in a pull request (PR).
27+
28+
## The contribution process
29+
30+
### Raise an issue
31+
32+
We encourage you to [raise an issue](https://github.com/Project-MONAI/tutorials/issues/new/choose) about your needs for MONAI tutorials.
33+
Conversations help better define the feature and allow other contributors in the community to provide feedback.
34+
35+
### Create a fork
36+
37+
When you are ready to kick off some coding, [create a new fork](https://github.com/Project-MONAI/tutorials/fork) of the `main` branch of this repository.
38+
39+
After forking is complete, you can `git clone` the forked repo to your development environment, and use `git checkout -b` to create a new branch to freely experiment with your changes.
40+
41+
For example:
42+
```bash
43+
git clone https://github.com/<your github space>/tutorials.git
44+
git checkout -b <your new branch name>
45+
```
46+
47+
### Create a new folder
48+
49+
MONAI tutorials covered examples of various medical applications and technical topics.
50+
Tutorials under the same topic/application share the same folder under the root directory, e.g. `2d_classification`, `2d_segmentation`, `3d_classification`, and `3d_segmentation`.
51+
52+
To hold your work in a new location, you can choose to create a new subfolder under the existing ones, or a folder under the root directory if it doesn't belong to any of the existing topics/applications.
53+
54+
The folder should have a `README.md` file with descriptive information for others to start using your code or tutorial notebooks.
55+
56+
Finally, the MONAI tutorial has a [README file](README.md) to communicate the important information and provide an overview of the tutorials and examples. For new tutorials, please add a new entry to the [List](README.md#4-list-of-notebooks-and-examples) of notebooks and [examples](README.md#4-list-of-notebooks-and-examples).
57+
58+
### Add license
59+
60+
All source code and notebook files should include copyright information at the top of the file.
61+
62+
NOTE: for Jupyter Notebook `.ipynb` files, the copyright information should appear at the top of the first markdown cell.
63+
There are extra two spaces at the end of each line to ensure no line auto-wrap in the markdown rendering in the display.
64+
65+
```markdown
66+
Copyright (c) MONAI Consortium
67+
Licensed under the Apache License, Version 2.0 (the "License");
68+
you may not use this file except in compliance with the License.
69+
You may obtain a copy of the License at
70+
http://www.apache.org/licenses/LICENSE-2.0
71+
Unless required by applicable law or agreed to in writing, software
72+
distributed under the License is distributed on an "AS IS" BASIS,
73+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
74+
See the License for the specific language governing permissions and
75+
limitations under the License.
76+
77+
```
78+
79+
### Create a notebook
80+
81+
Jupyter Notebook is the preferred way of writing a new MONAI tutorial because we encourage contributors to visualize the outputs and keep the records with the code.
82+
83+
Writing a notebook is easy and flexible, but we require all tutorial notebooks to start with the following three sections:
84+
85+
- Title of the notebook with [licensing information](#add-license) in one markdown cell
86+
- A markdown cell with `## Setup environment` and a code cell that executes `pip install` shell commands with the exclamation mark `!` to install all the packages necessary for your tutorial.
87+
88+
For example, we install [MONAI with extra dependencies](https://docs.monai.io/en/stable/installation.html#installing-the-recommended-dependencies) and `matplotlib` to set up the environment for the [mednist_tutorial](./2d_classification/mednist_tutorial.ipynb):
89+
90+
```
91+
!python -c "import monai" || pip install -q "monai-weekly[pillow, tqdm]"
92+
!python -c "import matplotlib" || pip install -q matplotlib
93+
```
94+
95+
- A markdown cell with `## Setup imports` and a code cell that contains **ALL** import statements and ends with `monai.config.print_config()`:
96+
97+
```python
98+
import numpy as np
99+
100+
from monai.config import print_config
101+
from monai.data import DataLoader
102+
...
103+
104+
print_config()
105+
```
106+
107+
Following this guideline, we prepare some [templates](.github/contributing_templates/notebook/README.md) for contributors to start with.
108+
109+
### Commit new changes
110+
111+
MONAI enforces the [Developer Certificate of Origin](https://developercertificate.org/) (DCO) on all pull requests.
112+
All commit messages should contain the `Signed-off-by` line with an email address.
113+
The [GitHub DCO app](https://github.com/apps/dco) is deployed on MONAI.
114+
The pull request's status will be `failed` if commits do not contain a valid `Signed-off-by` line.
115+
116+
Git has a `-s` (or `--signoff`) command-line option to append this automatically to your commit message:
117+
```bash
118+
git commit -s -m 'your awesome commit summary'
119+
```
120+
The commit message will be:
121+
```
122+
your awesome commit summary
123+
124+
Signed-off-by: Your Name <yourname@example.org>
125+
```
126+
127+
Full text of the DCO:
128+
```
129+
Developer Certificate of Origin
130+
Version 1.1
131+
132+
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
133+
1 Letterman Drive
134+
Suite D4700
135+
San Francisco, CA, 94129
136+
137+
Everyone is permitted to copy and distribute verbatim copies of this
138+
license document, but changing it is not allowed.
139+
140+
141+
Developer's Certificate of Origin 1.1
142+
143+
By making a contribution to this project, I certify that:
144+
145+
(a) The contribution was created in whole or in part by me and I
146+
have the right to submit it under the open source license
147+
indicated in the file; or
148+
149+
(b) The contribution is based upon previous work that, to the best
150+
of my knowledge, is covered under an appropriate open source
151+
license and I have the right under that license to submit that
152+
work with modifications, whether created in whole or in part
153+
by me, under the same open source license (unless I am
154+
permitted to submit under a different license), as indicated
155+
in the file; or
156+
157+
(c) The contribution was provided directly to me by some other
158+
person who certified (a), (b) or (c) and I have not modified
159+
it.
160+
161+
(d) I understand and agree that this project and the contribution
162+
are public and that a record of the contribution (including all
163+
personal information I submit with it, including my sign-off) is
164+
maintained indefinitely and may be redistributed consistent with
165+
this project or the open source license(s) involved.
166+
```
167+
168+
### Open a pull request
169+
170+
Once the changes are ready, push your local branch to the remote, e.g. `git push --set-upstream origin <your new branch name>`, and [open a pull request](https://github.com/Project-MONAI/tutorials/pulls).
171+
When the pull request is opened, the MONAI repository has a set of GitHub actions that will run checks on the changes.
172+
173+
Please check more [details in the guidelines](#ci-test-passing-guide) for how to pass the tests.
174+
175+
In addition, the team will perform diligent code reviews following this [set of guidelines](#common-recommendations-for-the-review) to reduce the amount of work for users to run the tutorials.
176+
177+
### Common recommendations for the review
178+
179+
Here are some recommendations to make your pull requests faster to review:
180+
- Note dataset availability. The contributor needs to provide info on how to access the dataset and make a note about the dataset's licensing info. For example, some datasets may be used for non-commercial purposes only. If the dataset can be directly downloaded from a public source on the internet, please consider using the folder specified by `MONAI_DATA_DIRECTORY` to store the dataset files as the [example notebook](.github/contributing_templates/notebook/example_feature.ipynb) shows.
181+
182+
- Avoid large files. Dataset files should be removed from the PR contribution. The overall size of the notebook should be kept down to a few megabytes.
183+
- Clean up long text outputs generated by Jupyter notebook code cells.
184+
- Remove private information from the notebook. For example, the user name in the file paths in the notebook outputs and metadata.
185+
- Be aware of the Hyperlink usage in the notebook:
186+
- Avoid linking MONAI tutorial resources in the repo using web links (instead, use relative file paths)
187+
- Avoid linking folders (folder links do not work well in Jupyter notebooks)
188+
- For graphs, it is recommended to download them and add them to the repo in the `./figure` folder under the root directory
189+
190+
If your tutorial includes network training pipelines, we encourage implementations to scale the training on multiple GPUs.
191+
For example, if you are using `torchrun` for multi-GPU training, please feel free to include the Python scripts in your tutorial.
192+
193+
## CI/CD test passing guide
194+
195+
The testing system uses `papermill` to run the notebooks.
196+
To verify the tutorial notebook locally, you can `pip install jupytext flake8 papermill` and then issue the following command with the full path to the notebook file.
197+
198+
```
199+
./runner.sh -t <path to your .ipynb file>
200+
```
201+
202+
NOTE: the argument after `-t` provides a filename for the `runner.sh` to locate a single notebook in the tutorial to run tests on.
203+
It is equivalent to using a regex pattern in the argument `-p` or `--pattern` to search for files to run checks.
204+
In this case, we can also use `-wholename` to specify the only notebook file we would like to check.
205+
The path must begin with `./`, for example:
206+
```
207+
./runner.sh -p "-and -wholename './2d_classification/mednist_tutorial.ipynb'"
208+
```
209+
210+
If you have multiple notebooks to test, please consider designing a regex pattern to locate all the notebook files and use `-p`.
211+
212+
The `runner.sh` includes three kinds of checks: PEP 8 Style, notebook execution, and format requirement.
213+
214+
### PEP 8 Style
215+
216+
PEP 8 is a set of guidelines for writing Python code.
217+
It was created to improve the readability and consistency of Python code, and to make it easier for people to understand and maintain.
218+
219+
The guidelines cover a wide range of topics, including naming conventions, indentation, white space, and comments.
220+
They also include recommendations for how to structure and format your code, as well as how to write comments and documentation.
221+
222+
PEP8 style is required for all Python code in `.py` script files and the cell blocks in Jupyter notebooks for the MONAI tutorial.
223+
Here is a set of common mistakes that lead to check failures:
224+
- A blank line at end of the cell
225+
- Extra blank spaces at the end of some lines
226+
- Module import is not in the `Setup import` cell
227+
- Import an unused module or create an unused variable
228+
It needs to note that `--autofix` needs a few additional packages to help you fix some of the issues automatically, and most others need your manual correction.
229+
230+
To run the PEP 8 tests locally, you can use this argument `--no-run` to run the scan only:
231+
232+
```
233+
./runner.sh -t <path to your .ipynb file> --no-run
234+
```
235+
236+
### Notebook execution
237+
238+
The CI/CD in the pull request process does not execute a Jupyter notebook.
239+
But the MONAI tutorial has scheduled scans to check if all notebooks can be executed regularly.
240+
241+
The notebook must be in a self-contained state, e.g. setting up the Python environment, downloading the dataset, performing the analysis, and preferably, cleaning up the intermediate files generated from the execution.
242+
243+
During integration testing, we run these notebooks.
244+
To save time, we modify variables to avoid unnecessary `for` loop iterations.
245+
For example, the testing system will search for `max_epoch` in the notebook, and set to value to `1` for faster notebook testing.
246+
247+
Hence, during training please use the variables:
248+
- `max_epochs` for the number of training epochs
249+
- `val_interval` for the validation interval
250+
251+
On the other hand, if the training is not part of your tutorial, or doesn't use the idea of epochs, please update the exclusion list of `doesnt_contain_max_epochs` in the [runner.sh](runner.sh).
252+
This lets the runner know that it's not a problem if it doesn't find `max_epochs`.
253+
254+
If you have any other variables that would benefit from setting them to `1` during testing, add them to `strings_to_replace` in `runner.sh`.
255+
These variables have been added to the list by other contributors:
256+
- `disc_train_interval` for GAN discriminator training inteval
257+
- `disc_train_steps` for GAN discriminator training steps
258+
- `num_batches_for_histogram`
259+
260+
Finally, if your tutorial is not suitable for automated testing, please exclude the notebook by updating the `skip_run_papermill` in the [runner.sh](runner.sh).
261+
You can append another line in the `skip_run_papermill`:
262+
```
263+
skip_run_papermill=("${skip_run_papermill[@]}" .*<name of your notebook>*)
264+
```
265+
266+
If `runner.sh` is modified in your PR, the file permission of `runner.sh` could be set incorrectly in some cases.
267+
Please ensure the file permission is set to `-rwxrwxr-x` so that our test system can load the script.
268+
For more information about how to change file permission in git version control, this [StackOverflow page](https://stackoverflow.com/questions/10516201/updating-and-committing-only-a-files-permissions-using-git-version-control) could be helpful.
269+
270+
### Format requirements
271+
272+
The CI/CD will check the following formats, in addition to PEP 8:
273+
- [Licensing information](#add-license)
274+
- [Environment and imports](#create-a-notebook)
275+
- [Output text length](#common-recommendations-for-the-review)
276+
277+
## Benchmarking result report
278+
279+
To standardize all result reporting, the MONAI team recommends contributors use A100 as the standard device for benchmarking in all notebooks.
280+
If contributors have difficulties getting the computation resources, please contact our team for support.

README.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,9 @@ Each user is responsible for checking the content of datasets and the applicable
5252
- For bugs relating to MONAI functionality, please create an issue on the [main repository](https://github.com/Project-MONAI/MONAI/issues).
5353
- For bugs relating to the running of a tutorial, please create an issue in [this repository](https://github.com/Project-MONAI/Tutorials/issues).
5454

55-
### 3. Note to developers
55+
### 3. Become a contributor
5656

57-
During integration testing, we run these notebooks. To save time, we modify variables to avoid unecessary `for` loop iterations. Hence, during training please use the variables `max_epochs` and `val_interval` for the number of training epochs and validation interval, respectively.
58-
59-
If your notebook doesn't use the idea of epochs, then please add it to the variable `doesnt_contain_max_epochs` in `runner.sh`. This lets the runner know that it's not a problem if it doesn't find `max_epochs`.
60-
61-
If you have any other variables that would benefit by setting them to `1` during testing, add them to `strings_to_replace` in `runner.sh`.
57+
You can read details about adding a tutorial in our [CONTRIBUTING GUIDELINES](CONTRIBUTING.md).
6258

6359
### 4. List of notebooks and examples
6460
#### <ins>**2D classification**</ins>

0 commit comments

Comments
 (0)