EasyTorch is a research-oriented pytorch prototyping framework with a straightforward learning curve. It is highly robust and contains almost everything needed to perform any state-of-the-art experiments.
pip install --upgrade pip
Install latest pytorch and torchvision from
Pytorchpip install easytorch
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)
python script.py -ph train -b 512 -e 10 -gpus 0
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')
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
python main.py -ph train -b 512 -e 10 -gpus 0
One can also directly pass arguments as below which overrides all.
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)
@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},
}