def add_numbers(*args):
return sum(args)Contribute
ReLax
This library uses nbdev for development. We love great flexibility offered by jupyter notebook, and nbdev in addressing limitations of using Notebook in developing large-scale projects (e.g., sync between notebooks and python modules, documentations).
Here, we only cover basis of our development procedure. For an in-depth use of nbdev, please refer to the nbdev tutorial. Following links are particularly useful:
Set up the working environment
Refer to installation guidance for installing ReLax. For running ReLax in CPU, you should
pip install jax-relaxNext, install Quarto for the documentation system. See nbdev docs for more details.
nbdev_install_quartoNext, install hooks for cleaning Jupyter Notebooks.
nbdev_install_hooks
Write Code in Jupyter Notebook
Note that nbdev provides a best practice guidline to writing code in Jupyter Notebooks. Here, we present some of the most important steps.
Export Cell to Python Module
#| export marks code cells (in Notebook; .ipynb) to be exported to Python Module (.py). By default, this cell will be exported to the file defined in #| default_exp file_name (usually presented upfront).
For example, the below function will be exported to the Python module.
#| export
def func(args):
...We can also specify files to be exported.
#| export file_name.py
def func(args):
...For private functions/objects, we can use #| exporti. In this way, the code will still be exported to the file, but not included in __all__.
More about directives.
Two-way Sync between Notebooks (.ipynb) and Python Code (.py)
To update code written in Jupyter Notebook to Python Module (i.e., .ipynb -> .py)
nbdev_exportTo sync code updated in Python Module back to Jupyter Notebook (i.e., .py -> .ipynb)
nbdev_updateIf you write a new function/object in .py, nbdev_update will not include this function in __all__. The best practice is to write functions/objects in Jupyter Notebook, and debug in Python Module (via IDE).
Code Style
ReLax follows the black code style. See black’s code style document.
Write Test Cases in Jupyter Notebook
It is desirable to write some unit tests for each function and object. nbdev recommends to write test cases after implementing a feature. A normal cell is considered for testing.
For example, let’s consider a function which adds up all the inputs:
To test this function, we write unit tests via assert.
# check correctness
assert add_numbers(1, 2, 3) == 6
# check types
assert type(add_numbers(1, 2, 3)) == int
assert type(add_numbers(1., 2, 3)) == floatNote that all the test cases should be quickly run. If a cell takes a long time to run (e.g., model training), mark the cell as #| eval: false to skip this cell.
Write Documentations in Jupyter Notebook
Doc string
To write documentations in nbdev, it is recommended to
- use simple type annotations
- describe each arguments with short comments
- provide code examples and explanations in separate cells
Union typing is introduced after Python 3.10. For Python 3.7 - 3.9 users, you should
from __future__ import annotationsdef validate_configs(
configs: dict|BaseParser, # A configuration of the model/data.
config_cls: BaseParser # The desired configuration class.
) -> BaseParser:
"""return a valid configuration object."""
...nbdev will automatically render the documentation:
validate_configs
validate_configs (configs:Union[dict,pydantic.main.BaseModel], config_cls:pydantic.main.BaseModel)
return a valid configuration object.
| Type | Details | |
|---|---|---|
| configs | dict | BaseParser | A configuration of the model/data. |
| config_cls | BaseParser | The desired configuration class. |
| Returns | BaseParser |
Next, we elaborate the use of this function with more descriptions and code examples.
We define a configuration object (which inherent BaseParser) to manage training/model/data configurations. validate_configs ensures to return the designated configuration object.
For example, we define a configuration object:
class LearningConfigs(BaseParser):
lr: floatA configuration can be LearningConfigs, or the raw data in dictionary.
configs = dict(lr=0.01)validate_configs will return a designated configuration object.
validate_configs(configs, LearningConfigs)LearningConfigs(lr=0.01)
Callout
We can also use callout for clear documentations.
:::{.callout-note}
Note that there are five types of callouts, including:
`note`, `warning`, `important`, `tip`, and `caution`.
:::which renders:
Note that there are five types of callouts, including: note, warning, important, tip, and caution.
Preparing a Code Commit
Preview the documentation system
nbdev_previewIf everything is in your satisfaction, prepare code before commit to GitHub
nbdev_prepareSummary
- Install all required packages based on installation guidance
- Install the git hook
nbdev_install_hooks - Write code in Jupyter Notebooks; add approprate directives, e.g.,
#| export - Write tests after the code in the Notebooks; test the code via
nbdev_test - Write documents directly in the Notebooks; preview the docs
nbdev_preview - Prepare changes with
nbdev_prepare - Create pull requests and push changes to GitHub