From a3eacdb9ce577cc614a29f41b7d5060d2e5c5023 Mon Sep 17 00:00:00 2001 From: San Askaruly Date: Wed, 18 Aug 2021 03:49:49 +0900 Subject: [PATCH] remove tests from folder --- README.md | 4 +- tests/Untitled.ipynb | 242 -------------------------- tests/alexnet_traineras.py | 346 ------------------------------------- tests/test_dirops.py | 35 ---- tests/test_imgops.py | 79 --------- tests/valid_x_A.png | Bin 19090 -> 0 bytes 6 files changed, 2 insertions(+), 704 deletions(-) delete mode 100644 tests/Untitled.ipynb delete mode 100644 tests/alexnet_traineras.py delete mode 100644 tests/test_dirops.py delete mode 100644 tests/test_imgops.py delete mode 100644 tests/valid_x_A.png diff --git a/README.md b/README.md index f5fe924..9b4a438 100644 --- a/README.md +++ b/README.md @@ -17,13 +17,13 @@ ## What's New ### August 18, 2021 -Release of [`farabio==0.0.2`](https://pypi.org/project/farabio/) +Release of [`farabio==0.0.2`](https://pypi.org/project/farabio/0.0.2/) ### April 21, 2021 This work is presented at PyTorch Ecosystem day. Poster is [here](https://pytorch.org/ecosystem/pted/2021). ### April 2, 2021 -Release of [`farabio==0.0.1`](https://pypi.org/project/farabio/) +Release of [`farabio==0.0.1`](https://pypi.org/project/farabio/0.0.1/) ### March 3, 2021 This work is selected for PyTorch Ecosystem Day. diff --git a/tests/Untitled.ipynb b/tests/Untitled.ipynb deleted file mode 100644 index c6adb2c..0000000 --- a/tests/Untitled.ipynb +++ /dev/null @@ -1,242 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "developed-heavy", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "armed-scale", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "coordinate-delight", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cleared-berkeley", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "revised-synthetic", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "velvet-going", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "major-sunday", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "superior-sphere", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "divine-jewel", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "greater-fiber", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "permanent-berlin", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "suspended-providence", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "failing-burns", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "superb-version", - "metadata": {}, - "outputs": [], - "source": [ - "#from farabio.data.biodatasets import RANZCRDataset\n", - "#from torch.utils.data import DataLoader\n", - "\n", - "#root = \"/home/data/02_SSD4TB/suzy/datasets/public\"\n", - "#train_dataset = RANZCRDataset(\n", - "# root=root, train=True, transform=None, download=False)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "incomplete-ceiling", - "metadata": {}, - "outputs": [], - "source": [ - "#train_dataset.visualize_dataset()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "acceptable-nightlife", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "spread-final", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "searching-thing", - "metadata": {}, - "outputs": [], - "source": [ - "#train_dataset.file_list[0][-1]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "chief-conflict", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "brief-jacket", - "metadata": {}, - "outputs": [], - "source": [ - "# random_idx = np.random.randint(1, len(train_list), size=16)\n", - "# fig, axes = plt.subplots(6,6, figsize=(13,13))\n", - "\n", - "# for idx, ax in enumerate(axes.ravel()):\n", - "# img = Image.open(train_list[idx][0])\n", - "# ax.set_title(train_list[idx][1])\n", - "# ax.imshow(img)\n", - "\n", - "# def visualize_dataset():\n", - "# \"\"\"\n", - "# Function to visualize images and masks\n", - "# \"\"\"\n", - " \n", - " \n", - "# root = \"/home/data/02_SSD4TB/suzy/datasets/public\"\n", - "\n", - "# train_dataset = RANZCRDataset(\n", - "# root=root, train=True, transform=None, download=False)\n", - "\n", - "# batch_size = 12\n", - "# train_loader = DataLoader(dataset = train_dataset, batch_size = batch_size, shuffle = True)\n", - "# inputs, classes = next(iter(train_loader))\n", - "# class_names = train_dataset.classes\n", - "\n", - "# #inputs, classes = next(iter(train_loader))\n", - "# out = torchvision.utils.make_grid(inputs)\n", - "# self.imshow(out, title=[class_names[x] for x in classes])\n", - "\n", - "# visualize_dataset()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "buried-iceland", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "acknowledged-certification", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.8" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/tests/alexnet_traineras.py b/tests/alexnet_traineras.py deleted file mode 100644 index bef14e5..0000000 --- a/tests/alexnet_traineras.py +++ /dev/null @@ -1,346 +0,0 @@ -import os -import time -import numpy as np -import torch -import torch.nn as nn -from torch.utils.data import Dataset, DataLoader, random_split -import albumentations as A -from albumentations.pytorch import ToTensor -from farabio.core.convnettrainer import ConvnetTrainer -from farabio.models.segmentation.unet.unet import Unet -from farabio.utils.regul import EarlyStopping -from farabio.utils.losses import Losses -from farabio.utils.tensorboard import TensorBoard -from farabio.utils.helpers import makedirs, parallel_state_dict -import skimage -import torchvision -from skimage import io, transform, img_as_ubyte -from skimage.io import imsave -from torchsummary import summary -from torchvision.datasets import ImageFolder -import torchvision.transforms as transforms -from farabio.data.biodatasets import DSB18Dataset -from farabio.utils.loggers import Logger, savefig -from farabio.utils.metrics import accuracy -from farabio.utils.meters import AverageMeter -import farabio.models.classification.conv as models -from progress.bar import Bar - - -class AlexTrainer(ConvnetTrainer): - """U-Net trainer class. Override with custom methods here. - - Parameters - ---------- - ConvnetTrainer : BaseTrainer - Inherits ConvnetTrainer class - """ - - def define_data_attr(self, *args): - self._title = self.config.title + self.config.arch - self._train_batch_size = self.config.batch_size_train - self._test_batch_size = self.config.batch_size_test - - def define_model_attr(self, *args): - self._arch = self.config.arch - self._cardinality = self.config.cardinality - self._num_classes = self.config.num_classes - self._depth = self.config.depth - self._widen_factor = self.config.widen_factor - self._drop_rate = self.config.dropout - self._growth_rate = self.config.growth_rate - self._compression_rate = self.config.compression_rate - self._block_name = self.config.block_name - - def define_train_attr(self): - self._lr = self.config.learning_rate - self._momentum = self.config.momentum - self._weight_decay = self.config.weight_decay - self._schedule = self.config.schedule - self._gamma = self.config.gamma - self._num_epochs = self._num_epochs - - def define_compute_attr(self, *args): - self._cuda = self.config.cuda - self._device = self.config.device - self._num_workers = self.config.num_workers - self._data_parallel = self.config.data_parallel - - def define_log_attr(self): - self.best_accuracy = 0 - self._checkpoint = self.config.checkpoint - - def get_trainloader(self): - transform_train = transforms.Compose([ - transforms.RandomCrop(32, padding=4), - transforms.RandomHorizontalFlip(), - transforms.ToTensor(), - transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), - ]) - trainset = torchvision.datasets.CIFAR10(root='/home/data/02_SSD4TB/suzy/datasets/public', train=True, download=False, transform=transform_train) - self.train_loader = DataLoader(trainset, batch_size=self._train_batch_size, shuffle=True, num_workers=self._num_workers) - - def get_testloader(self): - transform_test = transforms.Compose([ - transforms.ToTensor(), - transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), - ]) - testset = torchvision.datasets.CIFAR10(root='/home/data/02_SSD4TB/suzy/datasets/public', train=False, download=False, transform=transform_test) - self.test_loader = DataLoader(testset, batch_size=self._test_batch_size, shuffle=False, num_workers=self._num_workers) - - def build_model(self): - # Model - print("==> creating model '{}'".format(self._arch)) - if self._arch.startswith('resnext'): - self.model = models.__dict__[self._arch]( - cardinality=self._cardinality, - num_classes=self._num_classes, - depth=self._depth, - widen_factor=self._widen_factor, - dropRate=self._drop, - ) - elif self._arch.startswith('densenet'): - self.model = models.__dict__[self._arch]( - num_classes=self._num_classes, - depth=self._depth, - growthRate=self._growth_rate, - compressionRate=self._compression_rate, - dropRate=self._drop, - ) - elif self._arch.startswith('wrn'): - self.model = models.__dict__[self._arch]( - num_classes=self._num_classes, - depth=self._depth, - widen_factor=self._widen_factor, - dropRate=self._drop_rate, - ) - elif self._arch.endswith('resnet'): - self.model = models.__dict__[self._arch]( - num_classes=self._num_classes, - depth=self._depth, - block_name=self._block_name, - ) - else: - self.model = models.__dict__[self._arch](num_classes=self._num_classes) - - if self._cuda: - self.model.to(self._device) - - self.criterion = nn.CrossEntropyLoss() - self.optimizer = torch.optim.SGD(self.model.parameters(), lr=self._lr, momentum=self._momentum, weight_decay=self._weight_decay) - - def build_parallel_model(self): - # Model - print("==> creating model '{}'".format(self._arch)) - if self._arch.startswith('resnext'): - self.model = models.__dict__[self._arch]( - cardinality=self._cardinality, - num_classes=self._num_classes, - depth=self._depth, - widen_factor=self._widen_factor, - dropRate=self._drop, - ) - elif self._arch.startswith('densenet'): - self.model = models.__dict__[self._arch]( - num_classes=self._num_classes, - depth=self._depth, - growthRate=self._growth_rate, - compressionRate=self._compression_rate, - dropRate=self._drop, - ) - elif self._arch.startswith('wrn'): - self.model = models.__dict__[self._arch]( - num_classes=self._num_classes, - depth=self._depth, - widen_factor=self._widen_factor, - dropRate=self._drop_rate, - ) - elif self._arch.endswith('resnet'): - self.model = models.__dict__[self._arch]( - num_classes=self._num_classes, - depth=self._depth, - block_name=self._block_name, - ) - else: - self.model = models.__dict__[self._arch](num_classes=self._num_classes) - - self.model = torch.nn.DataParallel(self.model).cuda() - self.criterion = nn.CrossEntropyLoss() - self.optimizer = torch.optim.SGD(self.model.parameters(), lr=self._lr, momentum=self._momentum, weight_decay=self._weight_decay) - - def start_logger(self): - self.logger = Logger(os.path.join(self._checkpoint, 'log.txt'), title=self._title) - self.logger.set_names(['Learning Rate', 'Train Loss', 'Valid Loss', 'Train Acc.', 'Valid Acc.']) - - def on_train_epoch_start(self): - self.model.train() - - self.batch_time = AverageMeter() - self.data_time = AverageMeter() - self.losses = AverageMeter() - self.top1 = AverageMeter() - self.top5 = AverageMeter() - self.end = time.time() - - self.bar = Bar('Processing', max=len(self.train_loader)) - - self.adjust_learning_rate() - self.train_epoch_iter = enumerate(self.train_loader) - - print(f'\nEpoch: [{self._epoch + 1} | {self._num_epochs}] LR: {self._lr}') - - def on_start_training_batch(self, args): - self.batch_idx = args[0] - self.inputs = args[-1][0] - self.targets = args[-1][-1] - self.data_time.update(time.time() - self.end) - - def training_step(self): - if self._cuda: - self.inputs = self.inputs.to(self._device) - self.targets = self.targets.to(self._device) #async? - - self.inputs, self.targets = torch.autograd.Variable(self.inputs), torch.autograd.Variable(self.targets) - - self.outputs = self.model(self.inputs) - self.loss = self.criterion(self.outputs, self.targets) - prec1, prec5 = accuracy(self.outputs.data, self.targets.data, topk=(1, 5)) - - self.losses.update(self.loss.data[0], self.inputs.size(0)) - self.top1.update(prec1[0], self.inputs.size(0)) - self.top5.update(prec5[0], self.inputs.size(0)) - - self.optimizer_zero_grad() - self.loss_backward() - self.optimizer_step() - - def on_end_training_batch(self): - # measure elapsed time - self.batch_time.update(time.time() - self.end) - self.end = time.time() - - # plot progress - self.bar.suffix = '({batch}/{size}) Data: {data:.3f}s | Batch: {bt:.3f}s | Total: {total:} | ETA: {eta:} | Loss: {loss:.4f} | top1: {top1: .4f} | top5: {top5: .4f}'.format( - batch=self.batch_idx + 1, - size=len(self.train_loader), - data=self.data_time.avg, - bt=self.batch_time.avg, - total=self.bar.elapsed_td, - eta=self.bar.eta_td, - loss=self.losses.avg, - top1=self.top1.avg, - top5=self.top5.avg, - ) - - self.bar.next() - - def on_train_epoch_end(self): - self.bar.finish() - self.train_loss = self.losses.avg - self.train_accuracy = self.top1.avg - - def optimizer_zero_grad(self): - self.optimizer.zero_grad() - - def optimizer_step(self): - self.optimizer.step() - - def loss_backward(self): - self.loss.backward() - - def on_evaluate_epoch_start(self): - self.batch_time = AverageMeter() - self.data_time = AverageMeter() - self.losses = AverageMeter() - self.top1 = AverageMeter() - self.top5 = AverageMeter() - - self.model.eval() - - self.end = time.time() - self.valid_epoch_iter = enumerate(self.test_loader) - - self.bar = Bar('Processing', max=len(self.test_loader)) - - def on_evaluate_batch_start(self, args): - self.data_time.update(time.time() - self.end) - - self.batch_idx = args[0] - self.inputs = args[-1][0] - self.targets = args[-1][-1] - - def evaluate_batch(self, args): - if self._cuda: - self.inputs = self.inputs.to(self._device) - self.targets = self.targets.to(self._device) #async? - - self.inputs = torch.autograd.Variable(self.inputs, volatile=True) - self.targets = torch.autograd.Variable(self.targets) - - # compute output - self.outputs = self.model(self.inputs) - self.loss = self.criterion(self.outputs, self.targets) - - # measure accuracy and record loss - self.prec1, self.prec5 = accuracy(self.outputs.data, self.targets.data, topk=(1, 5)) - - def on_evaluate_batch_end(self): - self.losses.update(self.loss.data[0], self.inputs.size(0)) - self.top1.update(self.prec1[0], self.inputs.size(0)) - self.top5.update(self.prec5[0], self.inputs.size(0)) - # measure elapsed time - self.batch_time.update(time.time() - self.end) - self.end = time.time() - # plot progress - self.bar.suffix = '({batch}/{size}) Data: {data:.3f}s | Batch: {bt:.3f}s | Total: {total:} | ETA: {eta:} | Loss: {loss:.4f} | top1: {top1: .4f} | top5: {top5: .4f}'.format( - batch=self.batch_idx + 1, - size=len(self.test_loader), - data=self.data_time.avg, - bt=self.batch_time.avg, - total=self.bar.elapsed_td, - eta=self.bar.eta_td, - loss=self.losses.avg, - top1=self.top1.avg, - top5=self.top5.avg, - ) - self.bar.next() - - def on_evaluate_epoch_end(self): - self.bar.finish() - self.test_loss = self.losses.avg - self.test_accuracy = self.top1.avg - - def on_epoch_end(self): - # append logger file - self.logger.append([state['lr'], self.train_loss, self.test_loss, self.train_accuracy, self.test_accuracy]) - - # save model - is_best = self.test_accuracy > self.best_accuracy - self.best_accuracy = max(self.test_accuracy, self.best_accuracy) - self.save_checkpoint({ - 'epoch': self._epoch + 1, - 'state_dict': self.model.state_dict(), - 'acc': self.test_accuracy, - 'best_acc': self.best_accuracy, - 'optimizer' : self.optimizer.state_dict(), - }, is_best, checkpoint=self.config.checkpoint) - - def on_train_end(self): - self.logger.close() - self.logger.plot() - savefig(os.path.join(self._checkpoint, 'log.eps')) - - print('Best acc:') - print(self.best_accuracy) - - def adjust_learning_rate(self): - if self._epoch in self._schedule: - self._lr *= self._gamma - for param_group in self.optimizer.param_groups: - param_group['lr'] = self._lr - - def save_checkpoint(state, is_best, checkpoint='checkpoint', filename='checkpoint.pth.tar'): - filepath = os.path.join(checkpoint, filename) - torch.save(state, filepath) - if is_best: - shutil.copyfile(filepath, os.path.join(checkpoint, 'model_best.pth.tar')) \ No newline at end of file diff --git a/tests/test_dirops.py b/tests/test_dirops.py deleted file mode 100644 index 0e1a3ee..0000000 --- a/tests/test_dirops.py +++ /dev/null @@ -1,35 +0,0 @@ -import os -import unittest -from farabio.data.dirops import DirOps - - -class TestDirOps(unittest.TestCase): - def test_dirinfo(self): - sample_dir = './images/' - dir_object = DirOps(sample_dir) - print(dir_object.dirinfo()) - - def test_split_traintest(self): - sample_dir = './images/' - dir_object = DirOps(sample_dir) - test = dir_object.split_traintest()[0] - print(test) - - def test_lsmedia(self): - sample_dir = './images/' - dir_object = DirOps(sample_dir) - dir_object.lsmedia() - - def test_del_files(self): - sample_list = ['bitmap_font_1_basic.png', - 'bitmap_font_2_basic.png', 'bitmap_font_2_raqm.png'] - - sample_dir = './images/' - dir_object = DirOps(sample_dir) - dir_object.del_files(sample_list, match=False) - - print(os.listdir(sample_dir)) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_imgops.py b/tests/test_imgops.py deleted file mode 100644 index 131e00e..0000000 --- a/tests/test_imgops.py +++ /dev/null @@ -1,79 +0,0 @@ -import unittest -from farabio.data.imgops import ImgOps -import matplotlib.pyplot as plt - - -# you can display on server the result on server using X11 forwarding -class TestImgOps(unittest.TestCase): - # def test_init(self): - # sample_dir = './images/bitmap_font_8_raqm.png' - # img_object = ImgOps(sample_dir) - - # # plt.imshow(dir_object.img) - # # plt.show() - # print(img_object.h, img_object.w, img_object.ch) - - # def test_get_date(self): - # sample_dir = './images/2020-01-13-0056.jpg' - # img_object = ImgOps(sample_dir) - # print(img_object.get_date()) - - # def test_slice_img(self): - # sample_dir = './images/bitmap_font_8_raqm.png' - # img_object = ImgOps(sample_dir) - - # img_sl, img_sli = img_object.slice_img(2, 'y') - # plt.imshow(img_sl[0]) - # plt.show() - - # def test_pad_img(self): - # sample_dir = './images/bitmap_font_8_raqm.png' - # img_object = ImgOps(sample_dir) - - # pad_img = img_object.pad_img(droi=(500, 500), simg=None) - # plt.imshow(pad_img) - # plt.show() - - # def test_approx_bcg(self): - # # - # sample_dir = './images/approx_bcg.jpg' - # img_object = ImgOps(sample_dir) - - # approx_bcg = img_object.approx_bcg(channel='blue') - - # plt.imshow(approx_bcg) - # plt.show() - - # def test_blend_img(self): - # sample_img_dir = './images/argb-32bpp_MipMaps-1.png' - # sample_ref_dir = './images/bc7-argb-8bpp_MipMaps-1.png' - - # img_object = ImgOps(sample_img_dir) - # ref_img = ImgOps(sample_ref_dir).img - - # img_blended = img_object.blend_img(ref_img) - # plt.imshow(img_blended) - # plt.show() - - # def test_mask_img(self): - - # sample_img_dir = './images/plate_rgb.jpg' - # sample_mask_dir = './images/plate_mask.jpg' - - # img_object = ImgOps(sample_img_dir) - # mask_img = ImgOps(sample_mask_dir).img - - # img_ovr = img_object.mask_img(mask_img) - # plt.imshow(img_ovr) - # plt.show() - - def test_mask_img(self): - - sample_img_dir = './images/plate_rgb.jpg' - img_object = ImgOps(sample_img_dir) - - img_object.profile_img((0, 0), (50, 50)) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/valid_x_A.png b/tests/valid_x_A.png deleted file mode 100644 index 1753925938a62a2756d040d36c8128aad45f8a6f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19090 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