{"id":19352014,"url":"https://github.com/lukashedegaard/ride","last_synced_at":"2025-08-02T10:33:06.617Z","repository":{"id":38457478,"uuid":"335578904","full_name":"LukasHedegaard/ride","owner":"LukasHedegaard","description":"Training wheels, side rails, and helicopter parent for your Deep Learning projects in PyTorch","archived":false,"fork":false,"pushed_at":"2023-09-23T09:22:42.000Z","size":1491,"stargazers_count":25,"open_issues_count":1,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-05-31T21:17:22.745Z","etag":null,"topics":["ai","artificial-intelligence","deep-learning","framework","machine-learning","python","pytorch","pytorch-lightning"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LukasHedegaard.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2021-02-03T09:56:15.000Z","updated_at":"2024-09-27T09:55:25.000Z","dependencies_parsed_at":"2024-04-20T17:04:17.662Z","dependency_job_id":null,"html_url":"https://github.com/LukasHedegaard/ride","commit_stats":{"total_commits":293,"total_committers":4,"mean_commits":73.25,"dds":0.03412969283276446,"last_synced_commit":"f6f9aadd4070fd72d874b8e934c7e44f92c02d08"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/LukasHedegaard/ride","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LukasHedegaard%2Fride","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LukasHedegaard%2Fride/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LukasHedegaard%2Fride/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LukasHedegaard%2Fride/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LukasHedegaard","download_url":"https://codeload.github.com/LukasHedegaard/ride/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LukasHedegaard%2Fride/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268371301,"owners_count":24239788,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-02T02:00:12.353Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","artificial-intelligence","deep-learning","framework","machine-learning","python","pytorch","pytorch-lightning"],"created_at":"2024-11-10T04:37:52.449Z","updated_at":"2025-08-02T10:33:06.596Z","avatar_url":"https://github.com/LukasHedegaard.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/LukasHedegaard/ride/main/docs/figures/logo.svg\" width=\"350\", height=\"200\"\u003e\u003cbr\u003e\n\u003c/div\u003e\n\n\u003cdiv align=\"left\"\u003e\n  \u003ca href=\"https://pypi.org/project/ride/\"\u003e\n    \u003cimg src=\"https://img.shields.io/pypi/pyversions/ride\" height=\"20\" \u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://badge.fury.io/py/ride\"\u003e\n    \u003cimg src=\"https://badge.fury.io/py/ride.svg\" height=\"20\" \u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://pepy.tech/project/ride\"\u003e\n    \u003cimg src=\"https://static.pepy.tech/badge/ride\" height=\"20\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://www.codefactor.io/repository/github/lukashedegaard/ride\"\u003e\n    \u003cimg src=\"https://www.codefactor.io/repository/github/lukashedegaard/ride/badge\" alt=\"CodeFactor\" height=\"20\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://codecov.io/gh/LukasHedegaard/ride\"\u003e\n    \u003cimg src=\"https://codecov.io/gh/LukasHedegaard/ride/branch/main/graph/badge.svg?token=SJ59JOWNAC\" height=\"20\"/\u003e\n  \u003c/a\u003e\n  \u003ca href='https://ride.readthedocs.io/en/latest/?badge=latest'\u003e\n      \u003cimg src='https://readthedocs.org/projects/ride/badge/?version=latest' alt='Documentation Status' height=\"20\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://opensource.org/licenses/Apache-2.0\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/License-Apache%202.0-blue.svg\" height=\"20\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/psf/black\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/code%20style-black-000000.svg\" height=\"20\"\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n\n\nTraining wheels, side rails, and helicopter parent for your Deep Learning projects in [PyTorch](https://pytorch.org).\n\n```bash\npip install ride\n```\n\n## ZERO-boilerplate AI research \n`Ride` provides a feature-rich, battle-tested boilerplate, so that you can focus on the model-building and research. 🧪\n\nOut of the box, `Ride` gives you:\n- __Training and testing methods__ 🏋️‍♂️\n- __Checkpointing__ ✅\n- __Metrics__ 📈\n- __Finetuning schemes__ 👌\n- __Feature extraction__ 📸\n- __Visualisations__ 👁\n- __Hyperparameter search__ 📊\n- __Logging__ 📜\n- __Command-line interface__ 💻\n- __Multi-gpu, multi-node handling via__ \u003cimg src=\"https://img.shields.io/badge/PyTorch_Lightning-v1.4-643DD9.svg\" height=\"20\"\u003e\n- _... and more_\n\n\n\n## Boilerplate inheritance\nWith `Ride`, we inject functionality by means of _inheritance_. \nThe same way, your network would usually inherit from `torch.nn.Module`, we can _mix in_ a plethora of functionality by inheriting from the `RideModule` (which also includes the `torch.nn.Module`).\nIn addition, boiler-plate for wiring up optimisers, metrics and datasets can be also _mixed in_ as seen below.\n\n### Complete project definition\n\n```python\n# simple_classifier.py\nimport torch\nimport ride\nimport numpy as np\nfrom .examples import MnistDataset\n\n\nclass SimpleClassifier(\n    ride.RideModule,\n    ride.SgdOneCycleOptimizer, \n    ride.TopKAccuracyMetric(1,3),\n    MnistDataset,\n):\n    def __init__(self, hparams):\n        # `self.input_shape` and `self.output_shape` were injected via `MnistDataset`\n        self.l1 = torch.nn.Linear(np.prod(self.input_shape), self.hparams.hidden_dim)\n        self.l2 = torch.nn.Linear(self.hparams.hidden_dim, self.output_shape)\n\n    def forward(self, x):\n        x = x.view(x.size(0), -1)\n        x = torch.relu(self.l1(x))\n        x = torch.relu(self.l2(x))\n        return x\n\n    @staticmethod\n    def configs():\n        c = ride.Configs()\n        c.add(\n            name=\"hidden_dim\",\n            type=int,\n            default=128,\n            strategy=\"choice\",\n            choices=[128, 256, 512, 1024],\n            description=\"Number of hidden units.\",\n        )\n        return c\n\n\nif __name__ == \"__main__\":\n    ride.Main(SimpleClassifier).argparse()\n\n```\nThe above is the __complete__ code for a simple classifier on the MNIST dataset.\n\nAll of the usual boiler-plate code has been _mixed in_ using multiple inheritance:\n- `RideModule` is a base-module which includes `pl.LightningModule` and makes some behind-the-scenes python-magic work. For instance, it modifies your `__init__` function to automatically initiate all the mixins correctly. Moreover, it mixes in `training_step`, `validation_step`, and `test_step`.\n- `SgdOneCycleOptimizer` mixes in a `configure_optimizers` functionality with SGD and [OneCycleLR scheduler](https://pytorch.org/vision/0.8/datasets.html#torchvision.datasets.MNIST).\n- `TopKAccuracyMetric` adds top1acc and top3acc metrics, which can be used for checkpointing and benchmarking.\n- `MnistDataset` mixes in `train_dataloader`, `val_dataloader`, and `test_dataloader` functions for the [MNIST dataset](https://github.com/LukasHedegaard/co-rider). Dataset mixins always provide `input_shape` and `output_shape` attributes, which are handy for defining the networking structure as seen in `__init__`.\n\n## Configs\nIn addition to inheriting lifecycle functions etc., the mixins also add `configs` to your module (powered by [co-rider](https://github.com/LukasHedegaard/co-rider)). \nThese define all of the configurable (hyper)parameters including their\n- _type_ \n- _default_ value\n- _description_ in plain text (reflected in command-line interface),\n- _choices_ defines accepted input range\n- _strategy_ specifies how hyperparameter-search tackles the parameter. \n\nConfigs specific to the SimpleClassifier can be added by overloading the `configs` methods as shown in the example.\n\nThe final piece of sorcery is the `Main` class, which adds a complete command-line interface.\n\n\n## Command-line interface 💻\n### Train and test\n```shell\n$ python simple_classifier.py --train --test --learning_rate 0.01 --hidden_dim 256 --max_epochs 1\n```\n  - _Example output:_\n    ```shell\n    lightning: Global seed set to 123\n    ride: Running on host HostName\n    ride: ⭐️ View project repository at https://github.com/UserName/project_name/tree/commit_hash\n    ride: Run data is saved locally at /Users/UserName/project_name/logs/run_logs/your_id/version_1\n    ride: Logging using Tensorboard\n    ride: 💾 Saving /Users/au478108/Projects/ride/logs/run_logs/your_id/version_1/hparams.yaml\n    ride: 🚀 Running training\n    ride: ✅ Checkpointing on val/loss with optimisation direction min\n    lightning: GPU available: False, used: False\n    lightning: TPU available: False, using: 0 TPU cores\n    lightning: \n      | Name | Type   | Params\n    --------------------------------\n    0 | l1   | Linear | 200 K \n    1 | l2   | Linear | 2.6 K \n    --------------------------------\n    203 K     Trainable params\n    0         Non-trainable params\n    203 K     Total params\n    0.814     Total estimated model params size (MB)\n    lightning: Global seed set to 123                                                                                      \n\n    Epoch 0: 100%|████████| 3751/3751 [00:20\u003c00:00, 184.89it/s, loss=0.785, v_num=9, step_train/loss=0.762]\n    lightning: Epoch 0, global step 3437: val/loss reached 0.77671 (best 0.77671), saving model to \"/Users/UserName/project_name/logs/run_logs/your_id/version_1/checkpoints/epoch=0-step=3437.ckpt\" as top 1\n    lightning: Saving latest checkpoint...\n    Epoch 0: 100%|████████| 3751/3751 [00:20\u003c00:00, 184.65it/s, loss=0.785, v_num=9, step_train/loss=0.762]\n    ride: 🚀 Running evaluation on test set\n    Testing: 100%|████████| 625/625 [00:01\u003c00:00, 358.86it/s]\n    -------------------------------------\n    DATALOADER:0 TEST RESULTS\n    {'loss': 0.7508705258369446,\n    'test/loss': 0.7508705258369446,\n    'test/top1acc': 0.7986000180244446,\n    'test/top3acc': 0.8528000116348267}\n    -------------------------------------\n\n    ride: 💾 Saving /Users/UserName/project_name/logs/run_logs/your_id/version_1/test_results.yaml\n    ```\n\n\n### Feature extraction and visualisation\nExtract features after layer `l1` and visualise them with [UMAP](https://arxiv.org/abs/1802.03426).\n```shell\n$ python simple_classifier.py --train --test --extract_features_after_layer = \"l1\" --visualise_features = \"umap\"\n```\n- _Example output:_\n\n  \u003cdiv align=\"center\"\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/LukasHedegaard/ride/main/docs/figures/examples/mnist_umap.png\" width=\"300\"\u003e\n  \u003c/div\u003e\n  \n\n### Confusion matrix visualisation\nPlot the confution matrix for the test set.\n```shell\n$ python simple_classifier.py --train --test --test_confusion_matrix 1\n```\n- _Example output:_\n  \u003cdiv align=\"center\"\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/LukasHedegaard/ride/main/docs/figures/examples/mnist_confusion_matrix.png\" width=\"400\"\u003e\n  \u003c/div\u003e\n\n### Advanced model finetuning\nLoad model and finetune with [gradual unfreeze and discriminative learning rates](https://arxiv.org/abs/1801.06146)\n```shell\n$ python simple_classifier.py --train --finetune_from_weights your/path.ckpt --unfreeze_layers_initial 1 --unfreeze_epoch_step 1 --unfreeze_from_epoch 0 --discriminative_lr_fraction 0.1\n```\n\n### Hyperparameter optimization\nIf we want to perform __hyperparameter optimisation__  across four gpus, we can run:\n```shell\n$ python simple_classifier.py --hparamsearch --gpus 4\n```\nCurretly, we use [Ray Tune](https://docs.ray.io/en/master/tune.html) and the [ASHA](https://arxiv.org/abs/1810.05934) algorithm under the hood.\n\n### Profile model\nYou can check the __timing__ and __FLOPs__ of the model with:\n```shell\n$ python simple_classifier.py --profile_model\n```\n  - _Example output:_\n    \n    ```shell\n    Results:\n      flops: 203530\n      machine:\n        cpu:\n          architecture: x86_64\n          cores:\n            physical: 6\n            total: 12\n          frequency: 2.60 GHz\n          model: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz\n        gpus: null\n        memory:\n          available: 5.17 GB\n          total: 16.00 GB\n          used: 8.04 GB\n        system:\n          node: d40049\n          release: 19.6.0\n          system: Darwin\n      params: 203530\n      timing:\n        batch_size: 16\n        num_runs: 10000\n        on_gpu: false\n        samples_per_second: 88194.303 +/- 17581.377 [20177.049, 113551.377]\n        time_per_sample: 12.031us +/- 3.736us [8.807us, 49.561us]\n    ```\n\n\n### Additional options\nFor additional configuration options, check out the help:\n```shell\n$ python simple_classifier.py --help\n```\n  - _Truncated output:_\n    ```shell\n    Flow:\n      Commands that control the top-level flow of the programme.\n\n      --hparamsearch        Run hyperparameter search. The best hyperparameters\n                            will be used for subsequent lifecycle methods\n      --train               Run model training\n      --validate            Run model evaluation on validation set\n      --test                Run model evaluation on test set\n      --profile_model       Profile the model\n\n    General:\n      Settings that apply to the programme in general.\n\n      --id ID               Identifier for the run. If not specified, the current\n                            timestamp will be used (Default: 202101011337)\n      --seed SEED           Global random seed (Default: 123)\n      --logging_backend {tensorboard,wandb}\n                            Type of experiment logger (Default: tensorboard)\n      ...\n\n    Pytorch Lightning:\n      Settings inherited from the pytorch_lightning.Trainer\n      ...\n      --gpus GPUS           number of gpus to train on (int) or which GPUs to\n                            train on (list or str) applied per node\n      ...\n\n    Hparamsearch:\n      Settings associated with hyperparameter optimisation\n      ...\n\n    Module:\n      Settings associated with the Module\n      --loss {mse_loss,l1_loss,nll_loss,cross_entropy,binary_cross_entropy,...}\n                            Loss function used during optimisation. \n                            (Default: cross_entropy)\n      --batch_size BATCH_SIZE\n                            Dataloader batch size. (Default: 64)\n      --num_workers NUM_WORKERS\n                            Number of CPU workers to use for dataloading.\n                            (Default: 10)\n      --learning_rate LEARNING_RATE\n                            Learning rate. (Default: 0.1)\n      --weight_decay WEIGHT_DECAY\n                            Weight decay. (Default: 1e-05)\n      --momentum MOMENTUM   Momentum. (Default: 0.9)\n      --hidden_dim HIDDEN_DIM {128, 256, 512, 1024}\n                            Number of hidden units. (Defualt: 128)\n      --extract_features_after_layer EXTRACT_FEATURES_AFTER_LAYER\n                            Layer name after which to extract features. Nested\n                            layers may be selected using dot-notation, e.g.\n                            `block.subblock.layer1` (Default: )\n      --visualise_features {,umap,tsne,pca}\n                            Visualise extracted features using selected\n                            dimensionality reduction method. Visualisations are\n                            created only during evaluation. (Default: )\n      --finetune_from_weights FINETUNE_FROM_WEIGHTS\n                            Path to weights to finetune from. Allowed extension\n                            include {'.ckpt', '.pyth', '.pth', '.pkl',\n                            '.pickle'}. (Default: )\n      --unfreeze_from_epoch UNFREEZE_FROM_EPOCH\n                            Number of epochs to wait before starting gradual\n                            unfreeze. If -1, unfreeze is omitted. (Default: -1)\n      --test_confusion_matrix {0,1}\n                            Create and save confusion matrix for test data.\n                            (Default: 0)\n      ...\n    ```\n    Though the above `--help` printout was truncated for readibility, there's still a lot going on! \n    The general structure is a follows:\n    First, there are flags for controlling the programme flow (e.g. whether to run hparamsearch or training), then some general parameters (id, seed, etc.), all the parameters from Pytorch Lightning, hparamsearch-related arguments, and finally the Module-specific arguments, which we either specified in the `SimpleClassifier` or inherited from the RideModule and mixins. \n\n\n\n## Environment\nPer default, `Ride` projects are oriented around the current working directory and will save logs in the `~/logs folders`, and cache to `~/.cache`.\n\nThis behaviour can be overloaded by changing of the following environment variables (defaults noted):\n```bash\nROOT_PATH=\"~/\"\nCACHE_PATH=\".cache\"\nDATASETS_PATH=\"datasets\"  # Dir relative to ROOT_PATH\nLOGS_PATH=\"logs\"          # Dir relative to ROOT_PATH\nRUN_LOGS_PATH=\"run_logs\"  # Dir relative to LOGS_PATH\nTUNE_LOGS_PATH=\"tune_logs\"# Dir relative to LOGS_PATH\nLOG_LEVEL=\"INFO\"          # One of \"DEBUG\", \"INFO\", \"WARNING\", \"ERROR\", \"CRITICAL\"\n```\n\n\n## Examples\n### Library Examples\n- [SimpleClassifier](https://github.com/LukasHedegaard/ride/blob/main/examples/simple_classifier.py)\n- [MNIST Dataloader](https://github.com/LukasHedegaard/ride/blob/main/examples/mnist_dataset.py)\n\n### Community Examples\n\nVideo-based human action recognition:\n- [I3D](https://github.com/LukasHedegaard/co3d/tree/main/models/i3d)\n- [R(2+1)D](https://github.com/LukasHedegaard/co3d/tree/main/models/r2plus1d)\n- [SlowFast](https://github.com/LukasHedegaard/co3d/tree/main/models/slowfast)\n- [CoSlow](https://github.com/LukasHedegaard/co3d/tree/main/models/coslow)\n- [X3D](https://github.com/LukasHedegaard/co3d/tree/main/models/x3d)\n- [CoX3D](https://github.com/LukasHedegaard/co3d/tree/main/models/cox3d)\n\nSkeleton-based human action recognition:\n- [ST-GCN](https://github.com/LukasHedegaard/continual-skeletons/blob/main/models/st_gcn/st_gcn.py)\n- [CoST-GCN](https://github.com/LukasHedegaard/continual-skeletons/blob/main/models/cost_gcn/cost_gcn.py)\n- [A-GCN](https://github.com/LukasHedegaard/continual-skeletons/blob/main/models/a_gcn/a_gcn.py)\n- [CoA-GCN](https://github.com/LukasHedegaard/continual-skeletons/blob/main/models/coa_gcn/coa_gcn.py)\n- [S-Tr](https://github.com/LukasHedegaard/continual-skeletons/blob/main/models/s_tr/s_tr.py)\n- [CoS-Tr](https://github.com/LukasHedegaard/continual-skeletons/blob/main/models/cos_tr/cos_tr.py)\n\n\n## Citation\n\n### BibTeX\nIf you use `Ride` for your research and feel like citing it, here's a BibTex:\n\n```bibtex\n@article{hedegaard2021ride,\n  title={Ride},\n  author={Lukas Hedegaard},\n  journal={GitHub. Note: https://github.com/LukasHedegaard/ride},\n  year={2021}\n}\n```\n\n### Badge \u003ca href=\"https://github.com/LukasHedegaard/ride\"\u003e\u003cimg src=\"https://img.shields.io/badge/Built_to-Ride-643DD9.svg\" height=\"20\"\u003e\u003c/a\u003e\n\n\n.MD\n```md\n[![Ride](https://img.shields.io/badge/Built_to-Ride-643DD9.svg)](https://github.com/LukasHedegaard/ride)\n```\n\n.HTML\n```md\n\u003ca href=\"https://github.com/LukasHedegaard/ride\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Built_to-Ride-643DD9.svg\" height=\"20\"\u003e\n\u003c/a\u003e\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flukashedegaard%2Fride","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flukashedegaard%2Fride","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flukashedegaard%2Fride/lists"}