## A very lightweight framework on top of PyTorch with full functionality.
#### **Just one way of doing things means no learning curve.** ✅


[](https://github.com/sraashis/easytorch/actions)

<hr />
#### Installation
1. `pip install --upgrade pip`
2. `Install latest pytorch and torchvision from` [Pytorch](https://pytorch.org/)
3. `pip install easytorch`
* [MNIST](./examples/MNIST_easytorch_CNN.ipynb) [](https://colab.research.google.com/github//sraashis/easytorch/blob/master/examples/MNIST_easytorch_CNN.ipynb)
* [Retinal fundus image transfer learning tasks.](https://github.com/sraashis/retinal-fundus-transfer)
* [Covid-19 chest x-ray classification.](https://github.com/sraashis/covidxfactory)
* [DCGAN.](https://github.com/sraashis/gan-easytorch-celeb-faces)
#### Let's start with something simple like MNIST digit classification:
```python
from easytorch import EasyTorch, ETRunner, ConfusionMatrix, ETMeter
from torchvision import datasets, transforms
import torch.nn.functional as F
import torch
from examples.models import MNISTNet
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
class MNISTTrainer(ETRunner):
def _init_nn_model(self):
self.nn['model'] = MNISTNet()
def iteration(self, batch):
inputs, labels = batch[0].to(self.device['gpu']).float(), batch[1].to(self.device['gpu']).long()
out = self.nn['model'](inputs)
loss = F.nll_loss(out, labels)
_, pred = torch.max(out, 1)
meter = self.new_meter()
meter.averages.add(loss.item(), len(inputs))
meter.metrics['cfm'].add(pred, labels.float())
return {'loss': loss, 'meter': meter, 'predictions': pred}
def init_experiment_cache(self):
self.cache['log_header'] = 'Loss|Accuracy,F1,Precision,Recall'
self.cache.update(monitor_metric='f1', metric_direction='maximize')
def new_meter(self):
return ETMeter(
cfm=ConfusionMatrix(num_classes=10),
device=self.device['gpu']
)
if __name__ == "__main__":
train_dataset = datasets.MNIST('../data', train=True, download=True, transform=transform)
val_dataset = datasets.MNIST('../data', train=False, transform=transform)
dataloader_args = {'train': {'dataset': train_dataset}, 'validation': {'dataset': val_dataset}}
runner = EasyTorch(phase='train', batch_size=512,
epochs=10, gpus=[0], dataloader_args=dataloader_args)
runner.run(MNISTTrainer)
```
### Run as:
`python script.py -ph train -b 512 -e 10 -gpus 0`
### ... with **20+** useful options. Check [here](./easytorch/config/) for full list.
<hr />
## General use case:
#### 1. Define your trainer
```python
from easytorch import ETRunner, Prf1a, ETMeter, AUCROCMetrics
class MyTrainer(ETRunner):
def _init_nn_model(self):
self.nn['model'] = NeuralNetModel(out_size=self.conf['num_class'])
def iteration(self, batch):
"""Handle a single batch"""
"""Must have loss and meter"""
meter = self.new_meter()
...
return {'loss': ..., 'meter': ..., 'predictions': ...}
def new_meter(self):
return ETMeter(
num_averages=1,
prf1a=Prf1a(),
auc=AUCROCMetrics(),
device=self.device['gpu']
)
def init_cache(self):
"""Will plot Loss in one plot, and Accuracy,F1_score in another."""
self.cache['log_header'] = 'Loss|Accuracy,F1_score'
"""Model selection using validation set if present"""
self.cache.update(monitor_metric='f1', metric_direction='maximize')
````
* Method new_meter() returns ETMeter that takes any implementation of easytorch.meter.ETMetrics. Provided ones:
* easytorch.metrics.Prf1a() for binary classification that computes accuracy,f1,precision,recall, overlap/IOU.
* easytorch.metrics.ConfusionMatrix(num_classes=...) for multiclass classification that also computes global
accuracy,f1,precision,recall.
* easytorch.metrics.AUCROCMetrics for binary ROC-AUC score.
#### 2. Define specification for your datasets:
* EasyTorch automatically splits the training data in _**data_source**_ as specified by
_**split_ratio(-spl or --split-ratio 0.7, 0.15, 0.15, for train validation and test portion)**_ OR Custom splits in
1. Text files:
* data_source = "/some/path/*.txt", where it looks for 'train.txt', 'validation.txt', and 'test.txt' if phase is
_train_, and only 'test.txt' if phase is _test_
2. Json files:
* data_source = "some/path/split.json", where each split key has list of files as {'train': [], '
validation' :[], 'test':[]}
3. Just glob as data_source = "some/path/**/*.txt", must also provide split_ratio if phase = _train_
```python
from easytorch import ETDataset
class MyDataset(ETDataset):
def load_index(self, file):
"""(Optional) Load/Process something and add to diskcache as:
self.diskcahe.add(file, value)"""
"""This method runs in multiple processes by default"""
self.indices.append([file, 'something_extra'])
def __getitem__(self, index):
file = self.indices[index]
"""(Optional) Retrieve from diskcache as self.diskcache.get(file)"""
image = # Todo # Load file/Image.
label = # Todo # Load corresponding label.
# Extra preprocessing, if needed.
# Apply transforms, if needed.
return image, label
```
#### 3. Entry point (say main.py)
### Run as:
`python main.py -ph train -b 512 -e 10 -gpus 0`
One can also directly pass arguments as below which overrides all.
```python
from easytorch import EasyTorch
runner = EasyTorch(phase="train", batch_size=4, epochs=10,
gpus=[0], num_channel=1,
num_class=2, data_source="<some_data>/data_split.json")
runner.run(MyTrainer, MyDataset)
```
### All the best! Cheers! 🎉
#### Cite the following papers if you use this library:
```
@article{deepdyn_10.3389/fcomp.2020.00035,
title = {Dynamic Deep Networks for Retinal Vessel Segmentation},
author = {Khanal, Aashis and Estrada, Rolando},
year = 2020,
journal = {Frontiers in Computer Science},
volume = 2,
pages = 35,
doi = {10.3389/fcomp.2020.00035},
issn = {2624-9898}
}
@misc{2202.02382,
Author = {Aashis Khanal and Saeid Motevali and Rolando Estrada},
Title = {Fully Automated Tree Topology Estimation and Artery-Vein Classification},
Year = {2022},
Eprint = {arXiv:2202.02382},
}
```
### Feature Higlights:
* DataHandle that is always available, and decoupled from other modules enabling easy
customization ([ETDataHandle](easytorch/data/data.py)).
* Use custom & complex data handling mechanism.
* Simple lightweight logger/plotter.
* **Plot:** set log_header = 'Loss,F1,Accuracy' to plot in same plot or set log_header = 'Loss|F1,Accuracy' to plot
Loss in one plot, and F1,Accuracy in another plot.
* **Logs:** all arguments/generated data will be saved in logs.json file after the experiment finishes.
* Gradient accumulation, automatic logging/plotting, model checkpointing, save everything.
* Multiple metrics implementation at easytorch.metrics: Precision, Recall, Accuracy, Overlap, F1, ROC-AUC, Confusion
matrix
* **For advanced training with multiple networks, and complex training steps,
click [here](assets/AdvancedTraining.md):**
* **Implement custom metrics as [here](assets/CustomMetrics.md).**
Raw data
{
"_id": null,
"home_page": "https://github.com/sraashis/easytorch",
"name": "easytorch",
"maintainer": "",
"docs_url": null,
"requires_python": "",
"maintainer_email": "",
"keywords": "",
"author": "Aashis Khana1",
"author_email": "sraashis@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/5d/db/0b29bbd3da4ad3e7898a8f296389a00e1936f7f16317f5bccc41cca3347e/easytorch-3.8.5.tar.gz",
"platform": null,
"description": "## A very lightweight framework on top of PyTorch with full functionality.\n\n#### **Just one way of doing things means no learning curve.** \u2705\n\n\n\n\n[](https://github.com/sraashis/easytorch/actions)\n\n\n<hr />\n\n#### Installation\n\n1. `pip install --upgrade pip`\n2. `Install latest pytorch and torchvision from` [Pytorch](https://pytorch.org/)\n3. `pip install easytorch`\n\n* [MNIST](./examples/MNIST_easytorch_CNN.ipynb) [](https://colab.research.google.com/github//sraashis/easytorch/blob/master/examples/MNIST_easytorch_CNN.ipynb)\n* [Retinal fundus image transfer learning tasks.](https://github.com/sraashis/retinal-fundus-transfer)\n* [Covid-19 chest x-ray classification.](https://github.com/sraashis/covidxfactory)\n* [DCGAN.](https://github.com/sraashis/gan-easytorch-celeb-faces)\n\n#### Let's start with something simple like MNIST digit classification:\n\n```python\nfrom easytorch import EasyTorch, ETRunner, ConfusionMatrix, ETMeter\nfrom torchvision import datasets, transforms\nimport torch.nn.functional as F\nimport torch\nfrom examples.models import MNISTNet\n\ntransform = transforms.Compose([\n transforms.ToTensor(),\n transforms.Normalize((0.1307,), (0.3081,))\n])\n\n\nclass MNISTTrainer(ETRunner):\n def _init_nn_model(self):\n self.nn['model'] = MNISTNet()\n\n def iteration(self, batch):\n inputs, labels = batch[0].to(self.device['gpu']).float(), batch[1].to(self.device['gpu']).long()\n\n out = self.nn['model'](inputs)\n loss = F.nll_loss(out, labels)\n _, pred = torch.max(out, 1)\n\n meter = self.new_meter()\n meter.averages.add(loss.item(), len(inputs))\n meter.metrics['cfm'].add(pred, labels.float())\n\n return {'loss': loss, 'meter': meter, 'predictions': pred}\n\n def init_experiment_cache(self):\n self.cache['log_header'] = 'Loss|Accuracy,F1,Precision,Recall'\n self.cache.update(monitor_metric='f1', metric_direction='maximize')\n\n def new_meter(self):\n return ETMeter(\n cfm=ConfusionMatrix(num_classes=10),\n device=self.device['gpu']\n )\n\n\nif __name__ == \"__main__\":\n train_dataset = datasets.MNIST('../data', train=True, download=True, transform=transform)\n val_dataset = datasets.MNIST('../data', train=False, transform=transform)\n\n dataloader_args = {'train': {'dataset': train_dataset}, 'validation': {'dataset': val_dataset}}\n runner = EasyTorch(phase='train', batch_size=512,\n epochs=10, gpus=[0], dataloader_args=dataloader_args)\n runner.run(MNISTTrainer)\n```\n\n### Run as:\n\n`python script.py -ph train -b 512 -e 10 -gpus 0`\n\n### ... with **20+** useful options. Check [here](./easytorch/config/) for full list.\n\n<hr />\n\n## General use case:\n\n#### 1. Define your trainer\n\n```python\nfrom easytorch import ETRunner, Prf1a, ETMeter, AUCROCMetrics\n\n\nclass MyTrainer(ETRunner):\n\n def _init_nn_model(self):\n self.nn['model'] = NeuralNetModel(out_size=self.conf['num_class'])\n\n def iteration(self, batch):\n \"\"\"Handle a single batch\"\"\"\n \"\"\"Must have loss and meter\"\"\"\n meter = self.new_meter()\n ...\n return {'loss': ..., 'meter': ..., 'predictions': ...}\n\n def new_meter(self):\n return ETMeter(\n num_averages=1,\n prf1a=Prf1a(),\n auc=AUCROCMetrics(),\n device=self.device['gpu']\n )\n\n def init_cache(self):\n \"\"\"Will plot Loss in one plot, and Accuracy,F1_score in another.\"\"\"\n self.cache['log_header'] = 'Loss|Accuracy,F1_score'\n\n \"\"\"Model selection using validation set if present\"\"\"\n self.cache.update(monitor_metric='f1', metric_direction='maximize')\n\n````\n\n* Method new_meter() returns ETMeter that takes any implementation of easytorch.meter.ETMetrics. Provided ones:\n * easytorch.metrics.Prf1a() for binary classification that computes accuracy,f1,precision,recall, overlap/IOU.\n * easytorch.metrics.ConfusionMatrix(num_classes=...) for multiclass classification that also computes global\n accuracy,f1,precision,recall.\n * easytorch.metrics.AUCROCMetrics for binary ROC-AUC score.\n\n#### 2. Define specification for your datasets:\n\n* EasyTorch automatically splits the training data in _**data_source**_ as specified by\n _**split_ratio(-spl or --split-ratio 0.7, 0.15, 0.15, for train validation and test portion)**_ OR Custom splits in\n 1. Text files:\n * data_source = \"/some/path/*.txt\", where it looks for 'train.txt', 'validation.txt', and 'test.txt' if phase is\n _train_, and only 'test.txt' if phase is _test_\n 2. Json files:\n * data_source = \"some/path/split.json\", where each split key has list of files as {'train': [], '\n validation' :[], 'test':[]}\n 3. Just glob as data_source = \"some/path/**/*.txt\", must also provide split_ratio if phase = _train_\n\n```python\nfrom easytorch import ETDataset\n\n\nclass MyDataset(ETDataset):\n def load_index(self, file):\n \"\"\"(Optional) Load/Process something and add to diskcache as:\n self.diskcahe.add(file, value)\"\"\"\n \"\"\"This method runs in multiple processes by default\"\"\"\n\n self.indices.append([file, 'something_extra'])\n\n def __getitem__(self, index):\n file = self.indices[index]\n \"\"\"(Optional) Retrieve from diskcache as self.diskcache.get(file)\"\"\"\n\n image = # Todo # Load file/Image. \n label = # Todo # Load corresponding label.\n\n # Extra preprocessing, if needed.\n # Apply transforms, if needed.\n\n return image, label\n```\n\n#### 3. Entry point (say main.py)\n### Run as:\n\n`python main.py -ph train -b 512 -e 10 -gpus 0`\n\nOne can also directly pass arguments as below which overrides all.\n```python\nfrom easytorch import EasyTorch\n\nrunner = EasyTorch(phase=\"train\", batch_size=4, epochs=10,\n gpus=[0], num_channel=1, \n num_class=2, data_source=\"<some_data>/data_split.json\")\nrunner.run(MyTrainer, MyDataset)\n```\n\n### All the best! Cheers! \ud83c\udf89\n\n#### Cite the following papers if you use this library:\n\n```\n@article{deepdyn_10.3389/fcomp.2020.00035,\n\ttitle = {Dynamic Deep Networks for Retinal Vessel Segmentation},\n\tauthor = {Khanal, Aashis and Estrada, Rolando},\n\tyear = 2020,\n\tjournal = {Frontiers in Computer Science},\n\tvolume = 2,\n\tpages = 35,\n\tdoi = {10.3389/fcomp.2020.00035},\n\tissn = {2624-9898}\n}\n\n@misc{2202.02382,\n Author = {Aashis Khanal and Saeid Motevali and Rolando Estrada},\n Title = {Fully Automated Tree Topology Estimation and Artery-Vein Classification},\n Year = {2022},\n Eprint = {arXiv:2202.02382},\n}\n```\n\n### Feature Higlights:\n\n* DataHandle that is always available, and decoupled from other modules enabling easy\n customization ([ETDataHandle](easytorch/data/data.py)).\n * Use custom & complex data handling mechanism.\n* Simple lightweight logger/plotter.\n * **Plot:** set log_header = 'Loss,F1,Accuracy' to plot in same plot or set log_header = 'Loss|F1,Accuracy' to plot\n Loss in one plot, and F1,Accuracy in another plot.\n * **Logs:** all arguments/generated data will be saved in logs.json file after the experiment finishes.\n* Gradient accumulation, automatic logging/plotting, model checkpointing, save everything.\n* Multiple metrics implementation at easytorch.metrics: Precision, Recall, Accuracy, Overlap, F1, ROC-AUC, Confusion\n matrix\n* **For advanced training with multiple networks, and complex training steps,\n click [here](assets/AdvancedTraining.md):**\n* **Implement custom metrics as [here](assets/CustomMetrics.md).**\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Easy Neural Network Experiments with pytorch",
"version": "3.8.5",
"project_urls": {
"Homepage": "https://github.com/sraashis/easytorch"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "5ddb0b29bbd3da4ad3e7898a8f296389a00e1936f7f16317f5bccc41cca3347e",
"md5": "f55045e710b7ade2f486716083447429",
"sha256": "dc4110a15a702282d86f3788ea8fad7544c9c5fc4478a7eddb1869a5ca0cdfe9"
},
"downloads": -1,
"filename": "easytorch-3.8.5.tar.gz",
"has_sig": false,
"md5_digest": "f55045e710b7ade2f486716083447429",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 34655,
"upload_time": "2023-12-06T00:18:36",
"upload_time_iso_8601": "2023-12-06T00:18:36.317803Z",
"url": "https://files.pythonhosted.org/packages/5d/db/0b29bbd3da4ad3e7898a8f296389a00e1936f7f16317f5bccc41cca3347e/easytorch-3.8.5.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-12-06 00:18:36",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "sraashis",
"github_project": "easytorch",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [],
"lcname": "easytorch"
}