From 69279c5e563d47545168be5b6c59201ce96b1ca0 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 16 Apr 2024 01:15:25 +0000 Subject: [PATCH 01/91] Split train only in exist train and not exist valid --- src/netspresso_trainer/dataloaders/classification/dataset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/netspresso_trainer/dataloaders/classification/dataset.py b/src/netspresso_trainer/dataloaders/classification/dataset.py index ad84fa01b..bd7a12975 100644 --- a/src/netspresso_trainer/dataloaders/classification/dataset.py +++ b/src/netspresso_trainer/dataloaders/classification/dataset.py @@ -136,7 +136,7 @@ def load_samples(self): if exists_test: test_samples = self.load_data(split='test') - if not exists_valid: + if not exists_valid and exists_train: num_train_splitted = int(len(train_samples) * self.train_valid_split_ratio) train_samples, valid_samples = \ random_split(train_samples, [num_train_splitted, len(train_samples) - num_train_splitted], From 88051f558167e6456ce5c71b871bb3d7fbc86cd3 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 16 Apr 2024 02:20:45 +0000 Subject: [PATCH 02/91] Move data split loading logic to BaseDataSampler --- src/netspresso_trainer/dataloaders/base.py | 40 ++++++++++++++++++- .../dataloaders/detection/dataset.py | 30 ++------------ 2 files changed, 43 insertions(+), 27 deletions(-) diff --git a/src/netspresso_trainer/dataloaders/base.py b/src/netspresso_trainer/dataloaders/base.py index 8624e00cd..7b6044395 100644 --- a/src/netspresso_trainer/dataloaders/base.py +++ b/src/netspresso_trainer/dataloaders/base.py @@ -6,6 +6,7 @@ import numpy as np import torch import torch.utils.data as data +from loguru import logger class BaseCustomDataset(data.Dataset): @@ -114,10 +115,47 @@ def __init__(self, conf_data, train_valid_split_ratio): @abstractmethod def load_data(self): raise NotImplementedError + + @abstractmethod + def load_id_mapping(self): + raise NotImplementedError @abstractmethod - def load_samples(self): + def load_class_map(self, id_mapping): raise NotImplementedError + + def load_samples(self): + assert self.conf_data.id_mapping is not None + id_mapping = self.load_id_mapping() + idx_to_class = self.load_class_map(id_mapping) + + train_samples, valid_samples, test_samples = self.load_split_samples() + return train_samples, valid_samples, test_samples, {'idx_to_class': idx_to_class} + + def load_split_samples(self): + exists_train = self.conf_data.path.train.image is not None + exists_valid = self.conf_data.path.valid.image is not None + exists_test = self.conf_data.path.test.image is not None + + train_samples = None + valid_samples = None + test_samples = None + + if exists_train: + train_samples = self.load_data(split='train') + if exists_valid: + valid_samples = self.load_data(split='valid') + if exists_test: + test_samples = self.load_data(split='test') + + if not exists_valid and exists_train: + logger.info(f"Validation set is not provided in config. Split automatically training set by {self.train_valid_split_ratio:.1f}:{1-self.train_valid_split_ratio:.1f}.") + num_train_splitted = int(len(train_samples) * self.train_valid_split_ratio) + train_samples, valid_samples = \ + data.random_split(train_samples, [num_train_splitted, len(train_samples) - num_train_splitted], + generator=torch.Generator().manual_seed(42)) + + return train_samples, valid_samples, test_samples @abstractmethod def load_huggingface_samples(self): diff --git a/src/netspresso_trainer/dataloaders/detection/dataset.py b/src/netspresso_trainer/dataloaders/detection/dataset.py index ca9efcf9a..7d3e86f67 100644 --- a/src/netspresso_trainer/dataloaders/detection/dataset.py +++ b/src/netspresso_trainer/dataloaders/detection/dataset.py @@ -87,33 +87,11 @@ def load_data(self, split='train'): return images_and_targets - def load_samples(self): - assert self.conf_data.id_mapping is not None - id_mapping: Optional[list] = list(self.conf_data.id_mapping) - idx_to_class = load_custom_class_map(id_mapping=id_mapping) + def load_id_mapping(self): + return list(self.conf_data.id_mapping) - exists_train = self.conf_data.path.train.image is not None - exists_valid = self.conf_data.path.valid.image is not None - exists_test = self.conf_data.path.test.image is not None - - train_samples = None - valid_samples = None - test_samples = None - - if exists_train: - train_samples = self.load_data(split='train') - if exists_valid: - valid_samples = self.load_data(split='valid') - if exists_test: - test_samples = self.load_data(split='test') - - if not exists_valid: - num_train_splitted = int(len(train_samples) * self.train_valid_split_ratio) - train_samples, valid_samples = \ - random_split(train_samples, [num_train_splitted, len(train_samples) - num_train_splitted], - generator=torch.Generator().manual_seed(42)) - - return train_samples, valid_samples, test_samples, {'idx_to_class': idx_to_class} + def load_class_map(self, id_mapping): + return load_custom_class_map(id_mapping=id_mapping) def load_huggingface_samples(self): raise NotImplementedError From 840a37065c88d823150b35f71e3738c0eff766d5 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 16 Apr 2024 05:43:39 +0000 Subject: [PATCH 03/91] Update loading logic for all tasks --- src/netspresso_trainer/dataloaders/base.py | 4 +-- .../dataloaders/classification/dataset.py | 34 ++++--------------- .../dataloaders/detection/dataset.py | 2 +- .../dataloaders/pose_estimation/dataset.py | 31 +++-------------- .../dataloaders/segmentation/dataset.py | 33 ++++-------------- 5 files changed, 20 insertions(+), 84 deletions(-) diff --git a/src/netspresso_trainer/dataloaders/base.py b/src/netspresso_trainer/dataloaders/base.py index 7b6044395..d1512b5a8 100644 --- a/src/netspresso_trainer/dataloaders/base.py +++ b/src/netspresso_trainer/dataloaders/base.py @@ -127,10 +127,10 @@ def load_class_map(self, id_mapping): def load_samples(self): assert self.conf_data.id_mapping is not None id_mapping = self.load_id_mapping() - idx_to_class = self.load_class_map(id_mapping) + misc = self.load_class_map(id_mapping) train_samples, valid_samples, test_samples = self.load_split_samples() - return train_samples, valid_samples, test_samples, {'idx_to_class': idx_to_class} + return train_samples, valid_samples, test_samples, misc def load_split_samples(self): exists_train = self.conf_data.path.train.image is not None diff --git a/src/netspresso_trainer/dataloaders/classification/dataset.py b/src/netspresso_trainer/dataloaders/classification/dataset.py index bd7a12975..74b1f3466 100644 --- a/src/netspresso_trainer/dataloaders/classification/dataset.py +++ b/src/netspresso_trainer/dataloaders/classification/dataset.py @@ -20,7 +20,7 @@ def load_custom_class_map(id_mapping: List[str]): idx_to_class: Dict[int, str] = dict(enumerate(id_mapping)) - return idx_to_class + return {'idx_to_class': idx_to_class} def load_class_map_with_id_mapping(labels_path: Optional[Union[str, Path]]): @@ -115,34 +115,12 @@ def load_data(self, split='train'): images_and_targets = sorted(images_and_targets, key=lambda k: natural_key(k['image'])) return images_and_targets + + def load_id_mapping(self): + return list(self.conf_data.id_mapping) - def load_samples(self): - assert self.conf_data.id_mapping is not None - id_mapping = list(self.conf_data.id_mapping) - idx_to_class = load_custom_class_map(id_mapping=id_mapping) - - exists_train = self.conf_data.path.train.image is not None - exists_valid = self.conf_data.path.valid.image is not None - exists_test = self.conf_data.path.test.image is not None - - train_samples = None - valid_samples = None - test_samples = None - - if exists_train: - train_samples = self.load_data(split='train') - if exists_valid: - valid_samples = self.load_data(split='valid') - if exists_test: - test_samples = self.load_data(split='test') - - if not exists_valid and exists_train: - num_train_splitted = int(len(train_samples) * self.train_valid_split_ratio) - train_samples, valid_samples = \ - random_split(train_samples, [num_train_splitted, len(train_samples) - num_train_splitted], - generator=torch.Generator().manual_seed(42)) - - return train_samples, valid_samples, test_samples, {'idx_to_class': idx_to_class} + def load_class_map(self, id_mapping): + return load_custom_class_map(id_mapping=id_mapping) def load_huggingface_samples(self): from datasets import ClassLabel, load_dataset diff --git a/src/netspresso_trainer/dataloaders/detection/dataset.py b/src/netspresso_trainer/dataloaders/detection/dataset.py index 7d3e86f67..3c4fefa23 100644 --- a/src/netspresso_trainer/dataloaders/detection/dataset.py +++ b/src/netspresso_trainer/dataloaders/detection/dataset.py @@ -17,7 +17,7 @@ def load_custom_class_map(id_mapping: List[str]): idx_to_class: Dict[int, str] = dict(enumerate(id_mapping)) - return idx_to_class + return {'idx_to_class': idx_to_class} def detection_collate_fn(original_batch): indices = [] diff --git a/src/netspresso_trainer/dataloaders/pose_estimation/dataset.py b/src/netspresso_trainer/dataloaders/pose_estimation/dataset.py index 2e5a21c1d..73822538f 100644 --- a/src/netspresso_trainer/dataloaders/pose_estimation/dataset.py +++ b/src/netspresso_trainer/dataloaders/pose_estimation/dataset.py @@ -17,7 +17,7 @@ def load_custom_class_map(id_mapping: List[str]): idx_to_class: Dict[int, str] = dict(enumerate(id_mapping)) - return idx_to_class + return {'idx_to_class': idx_to_class} class PoseEstimationDataSampler(BaseDataSampler): @@ -55,32 +55,11 @@ def load_data(self, split='train'): return images_and_targets - def load_samples(self): - assert self.conf_data.id_mapping is not None - id_mapping: Optional[list] = list(self.conf_data.id_mapping) - idx_to_class = load_custom_class_map(id_mapping=id_mapping) + def load_id_mapping(self): + return list(self.conf_data.id_mapping) - exists_train = self.conf_data.path.train.image is not None - exists_valid = self.conf_data.path.valid.image is not None - exists_test = self.conf_data.path.test.image is not None - - train_samples = None - valid_samples = None - test_samples = None - - if exists_train: - train_samples = self.load_data(split='train') - if exists_valid: - valid_samples = self.load_data(split='valid') - if exists_test: - test_samples = self.load_data(split='test') - - if not exists_valid: - num_train_splitted = int(len(train_samples) * self.train_valid_split_ratio) - train_samples, valid_samples = random_split(train_samples, [num_train_splitted, len(train_samples) - num_train_splitted], - generator=torch.Generator().manual_seed(42)) - - return train_samples, valid_samples, test_samples, {'idx_to_class': idx_to_class} + def load_class_map(self, id_mapping): + return load_custom_class_map(id_mapping=id_mapping) def load_huggingface_samples(self): raise NotImplementedError diff --git a/src/netspresso_trainer/dataloaders/segmentation/dataset.py b/src/netspresso_trainer/dataloaders/segmentation/dataset.py index 74b54fcf4..5e52a4269 100644 --- a/src/netspresso_trainer/dataloaders/segmentation/dataset.py +++ b/src/netspresso_trainer/dataloaders/segmentation/dataset.py @@ -44,7 +44,7 @@ def load_custom_class_map(id_mapping: Union[ListConfig, DictConfig]) -> Tuple[Di idx_to_class[class_idx] = class_name label_value_to_idx[label_value_tuple] = class_idx - return idx_to_class, label_value_to_idx + return {'idx_to_class': idx_to_class, 'label_value_to_idx': label_value_to_idx} class SegmentationDataSampler(BaseDataSampler): @@ -78,32 +78,11 @@ def load_data(self, split='train'): return images_and_targets - def load_samples(self): - assert isinstance(self.conf_data.id_mapping, (ListConfig, DictConfig)) - - idx_to_class, label_value_to_idx = load_custom_class_map(id_mapping=self.conf_data.id_mapping) - - exists_train = self.conf_data.path.train.image is not None - exists_valid = self.conf_data.path.valid.image is not None - exists_test = self.conf_data.path.test.image is not None - - train_samples = None - valid_samples = None - test_samples = None - - if exists_train: - train_samples = self.load_data(split='train') - if exists_valid: - valid_samples = self.load_data(split='valid') - if exists_test: - test_samples = self.load_data(split='test') - - if not exists_valid: - num_train_splitted = int(len(train_samples) * self.train_valid_split_ratio) - train_samples, valid_samples = random_split(train_samples, [num_train_splitted, len(train_samples) - num_train_splitted], - generator=torch.Generator().manual_seed(42)) - - return train_samples, valid_samples, test_samples, {'idx_to_class': idx_to_class, 'label_value_to_idx': label_value_to_idx} + def load_id_mapping(self): + return self.conf_data.id_mapping + + def load_class_map(self, id_mapping): + return load_custom_class_map(id_mapping=id_mapping) def load_huggingface_samples(self): from datasets import load_dataset From acc4527aa32556d03a6ec91da92367fc90533b05 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 16 Apr 2024 05:51:10 +0000 Subject: [PATCH 04/91] Move load_custom_class_map into class method --- .../dataloaders/classification/dataset.py | 8 +-- .../dataloaders/detection/dataset.py | 7 +-- .../dataloaders/pose_estimation/dataset.py | 8 +-- .../dataloaders/segmentation/dataset.py | 54 +++++++++---------- 4 files changed, 31 insertions(+), 46 deletions(-) diff --git a/src/netspresso_trainer/dataloaders/classification/dataset.py b/src/netspresso_trainer/dataloaders/classification/dataset.py index 74b1f3466..f6c653134 100644 --- a/src/netspresso_trainer/dataloaders/classification/dataset.py +++ b/src/netspresso_trainer/dataloaders/classification/dataset.py @@ -18,11 +18,6 @@ VALID_IMG_EXTENSIONS = IMG_EXTENSIONS + tuple((x.upper() for x in IMG_EXTENSIONS)) -def load_custom_class_map(id_mapping: List[str]): - idx_to_class: Dict[int, str] = dict(enumerate(id_mapping)) - return {'idx_to_class': idx_to_class} - - def load_class_map_with_id_mapping(labels_path: Optional[Union[str, Path]]): # Assume the `map_or_filename` is path for csv label file assert labels_path.exists(), f"Cannot locate specified class map file {labels_path}!" @@ -120,7 +115,8 @@ def load_id_mapping(self): return list(self.conf_data.id_mapping) def load_class_map(self, id_mapping): - return load_custom_class_map(id_mapping=id_mapping) + idx_to_class: Dict[int, str] = dict(enumerate(id_mapping)) + return {'idx_to_class': idx_to_class} def load_huggingface_samples(self): from datasets import ClassLabel, load_dataset diff --git a/src/netspresso_trainer/dataloaders/detection/dataset.py b/src/netspresso_trainer/dataloaders/detection/dataset.py index 3c4fefa23..49cd2e164 100644 --- a/src/netspresso_trainer/dataloaders/detection/dataset.py +++ b/src/netspresso_trainer/dataloaders/detection/dataset.py @@ -15,10 +15,6 @@ from ..utils.misc import natural_key -def load_custom_class_map(id_mapping: List[str]): - idx_to_class: Dict[int, str] = dict(enumerate(id_mapping)) - return {'idx_to_class': idx_to_class} - def detection_collate_fn(original_batch): indices = [] pixel_values = [] @@ -91,7 +87,8 @@ def load_id_mapping(self): return list(self.conf_data.id_mapping) def load_class_map(self, id_mapping): - return load_custom_class_map(id_mapping=id_mapping) + idx_to_class: Dict[int, str] = dict(enumerate(id_mapping)) + return {'idx_to_class': idx_to_class} def load_huggingface_samples(self): raise NotImplementedError diff --git a/src/netspresso_trainer/dataloaders/pose_estimation/dataset.py b/src/netspresso_trainer/dataloaders/pose_estimation/dataset.py index 73822538f..2973269f7 100644 --- a/src/netspresso_trainer/dataloaders/pose_estimation/dataset.py +++ b/src/netspresso_trainer/dataloaders/pose_estimation/dataset.py @@ -15,11 +15,6 @@ from ..utils.misc import natural_key -def load_custom_class_map(id_mapping: List[str]): - idx_to_class: Dict[int, str] = dict(enumerate(id_mapping)) - return {'idx_to_class': idx_to_class} - - class PoseEstimationDataSampler(BaseDataSampler): def __init__(self, conf_data, train_valid_split_ratio): super(PoseEstimationDataSampler, self).__init__(conf_data, train_valid_split_ratio) @@ -59,7 +54,8 @@ def load_id_mapping(self): return list(self.conf_data.id_mapping) def load_class_map(self, id_mapping): - return load_custom_class_map(id_mapping=id_mapping) + idx_to_class: Dict[int, str] = dict(enumerate(id_mapping)) + return {'idx_to_class': idx_to_class} def load_huggingface_samples(self): raise NotImplementedError diff --git a/src/netspresso_trainer/dataloaders/segmentation/dataset.py b/src/netspresso_trainer/dataloaders/segmentation/dataset.py index 5e52a4269..e66a2c651 100644 --- a/src/netspresso_trainer/dataloaders/segmentation/dataset.py +++ b/src/netspresso_trainer/dataloaders/segmentation/dataset.py @@ -21,32 +21,6 @@ def as_tuple(tuple_string: str) -> Tuple: return tuple_value -def load_custom_class_map(id_mapping: Union[ListConfig, DictConfig]) -> Tuple[Dict[int, str], Dict[Union[int, Tuple], int]]: - if isinstance(id_mapping, ListConfig): - assert isinstance(id_mapping[0], str), f"Unknown type for class name! {type(id_mapping[0])}" - idx_to_class: Dict[int, str] = dict(enumerate(id_mapping)) - label_value_to_idx = {k: k for k in idx_to_class} - return idx_to_class, label_value_to_idx - - idx_to_class: Dict[int, str] = {} - label_value_to_idx: Dict[Union[int, Tuple], int] = {} - for class_idx, (label_value, class_name) in enumerate(id_mapping.items()): - assert isinstance(class_name, str), "You need to format id_mapping with key for class_index, value for class_name." - if isinstance(label_value, (int, tuple)): - idx_to_class[class_idx] = class_name - label_value_to_idx[label_value] = class_idx - continue - - # Check tuple string - assert isinstance(label_value, str) and label_value.strip().startswith("(") and label_value.strip().endswith(")"), \ - f"Unknown type for color index! Should be one of (int, tuple-style str, tuple)... but {type(label_value)}" - label_value_tuple: Tuple[int, int, int] = as_tuple(label_value) - idx_to_class[class_idx] = class_name - label_value_to_idx[label_value_tuple] = class_idx - - return {'idx_to_class': idx_to_class, 'label_value_to_idx': label_value_to_idx} - - class SegmentationDataSampler(BaseDataSampler): def __init__(self, conf_data, train_valid_split_ratio): super(SegmentationDataSampler, self).__init__(conf_data, train_valid_split_ratio) @@ -82,7 +56,29 @@ def load_id_mapping(self): return self.conf_data.id_mapping def load_class_map(self, id_mapping): - return load_custom_class_map(id_mapping=id_mapping) + if isinstance(id_mapping, ListConfig): + assert isinstance(id_mapping[0], str), f"Unknown type for class name! {type(id_mapping[0])}" + idx_to_class: Dict[int, str] = dict(enumerate(id_mapping)) + label_value_to_idx = {k: k for k in idx_to_class} + return idx_to_class, label_value_to_idx + + idx_to_class: Dict[int, str] = {} + label_value_to_idx: Dict[Union[int, Tuple], int] = {} + for class_idx, (label_value, class_name) in enumerate(id_mapping.items()): + assert isinstance(class_name, str), "You need to format id_mapping with key for class_index, value for class_name." + if isinstance(label_value, (int, tuple)): + idx_to_class[class_idx] = class_name + label_value_to_idx[label_value] = class_idx + continue + + # Check tuple string + assert isinstance(label_value, str) and label_value.strip().startswith("(") and label_value.strip().endswith(")"), \ + f"Unknown type for color index! Should be one of (int, tuple-style str, tuple)... but {type(label_value)}" + label_value_tuple: Tuple[int, int, int] = as_tuple(label_value) + idx_to_class[class_idx] = class_name + label_value_to_idx[label_value_tuple] = class_idx + + return {'idx_to_class': idx_to_class, 'label_value_to_idx': label_value_to_idx} def load_huggingface_samples(self): from datasets import load_dataset @@ -97,7 +93,7 @@ def load_huggingface_samples(self): assert isinstance(self.conf_data.id_mapping, (ListConfig, DictConfig)) - idx_to_class, label_value_to_idx = load_custom_class_map(id_mapping=self.conf_data.id_mapping) + misc = self.load_class_map(id_mapping=self.conf_data.id_mapping) exists_valid = 'validation' in total_dataset exists_test = 'test' in total_dataset @@ -114,4 +110,4 @@ def load_huggingface_samples(self): splitted_datasets = train_samples.train_test_split(test_size=(1 - self.train_valid_split_ratio)) train_samples = splitted_datasets['train'] valid_samples = splitted_datasets['test'] - return train_samples, valid_samples, test_samples, {'idx_to_class': idx_to_class, 'label_value_to_idx': label_value_to_idx} + return train_samples, valid_samples, test_samples, misc From 22b687cc724a81c8bb759a43281eed5d42672702 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 16 Apr 2024 07:12:35 +0000 Subject: [PATCH 05/91] Rename DataSampler to SampleLoader --- src/netspresso_trainer/dataloaders/base.py | 2 +- .../dataloaders/classification/dataset.py | 6 +++--- src/netspresso_trainer/dataloaders/detection/dataset.py | 6 +++--- .../dataloaders/pose_estimation/dataset.py | 6 +++--- src/netspresso_trainer/dataloaders/segmentation/dataset.py | 6 +++--- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/netspresso_trainer/dataloaders/base.py b/src/netspresso_trainer/dataloaders/base.py index d1512b5a8..69007095e 100644 --- a/src/netspresso_trainer/dataloaders/base.py +++ b/src/netspresso_trainer/dataloaders/base.py @@ -107,7 +107,7 @@ def with_label(self): return self._with_label -class BaseDataSampler(ABC): +class BaseSampleLoader(ABC): def __init__(self, conf_data, train_valid_split_ratio): self.conf_data = conf_data self.train_valid_split_ratio = train_valid_split_ratio diff --git a/src/netspresso_trainer/dataloaders/classification/dataset.py b/src/netspresso_trainer/dataloaders/classification/dataset.py index f6c653134..fdb544427 100644 --- a/src/netspresso_trainer/dataloaders/classification/dataset.py +++ b/src/netspresso_trainer/dataloaders/classification/dataset.py @@ -11,7 +11,7 @@ from torch.nn import functional as F from torch.utils.data import random_split -from ..base import BaseDataSampler +from ..base import BaseSampleLoader from ..utils.constants import IMG_EXTENSIONS from ..utils.misc import natural_key @@ -82,9 +82,9 @@ def classification_onehot_collate_fn(original_batch, num_classes): return outputs -class ClassficationDataSampler(BaseDataSampler): +class ClassficationSampleLoader(BaseSampleLoader): def __init__(self, conf_data, train_valid_split_ratio): - super(ClassficationDataSampler, self).__init__(conf_data, train_valid_split_ratio) + super(ClassficationSampleLoader, self).__init__(conf_data, train_valid_split_ratio) def load_data(self, split='train'): data_root = Path(self.conf_data.path.root) diff --git a/src/netspresso_trainer/dataloaders/detection/dataset.py b/src/netspresso_trainer/dataloaders/detection/dataset.py index 49cd2e164..558cacd91 100644 --- a/src/netspresso_trainer/dataloaders/detection/dataset.py +++ b/src/netspresso_trainer/dataloaders/detection/dataset.py @@ -10,7 +10,7 @@ from omegaconf import DictConfig from torch.utils.data import random_split -from ..base import BaseDataSampler +from ..base import BaseSampleLoader from ..utils.constants import IMG_EXTENSIONS from ..utils.misc import natural_key @@ -48,9 +48,9 @@ def detection_collate_fn(original_batch): return outputs -class DetectionDataSampler(BaseDataSampler): +class DetectionSampleLoader(BaseSampleLoader): def __init__(self, conf_data, train_valid_split_ratio): - super(DetectionDataSampler, self).__init__(conf_data, train_valid_split_ratio) + super(DetectionSampleLoader, self).__init__(conf_data, train_valid_split_ratio) def load_data(self, split='train'): assert split in ['train', 'valid', 'test'], f"split should be either {['train', 'valid', 'test']}." diff --git a/src/netspresso_trainer/dataloaders/pose_estimation/dataset.py b/src/netspresso_trainer/dataloaders/pose_estimation/dataset.py index 2973269f7..cacb8c3b7 100644 --- a/src/netspresso_trainer/dataloaders/pose_estimation/dataset.py +++ b/src/netspresso_trainer/dataloaders/pose_estimation/dataset.py @@ -10,14 +10,14 @@ from omegaconf import DictConfig from torch.utils.data import random_split -from ..base import BaseDataSampler +from ..base import BaseSampleLoader from ..utils.constants import IMG_EXTENSIONS from ..utils.misc import natural_key -class PoseEstimationDataSampler(BaseDataSampler): +class PoseEstimationSampleLoader(BaseSampleLoader): def __init__(self, conf_data, train_valid_split_ratio): - super(PoseEstimationDataSampler, self).__init__(conf_data, train_valid_split_ratio) + super(PoseEstimationSampleLoader, self).__init__(conf_data, train_valid_split_ratio) def load_data(self, split='train'): assert split in ['train', 'valid', 'test'], f"split should be either {['train', 'valid', 'test']}." diff --git a/src/netspresso_trainer/dataloaders/segmentation/dataset.py b/src/netspresso_trainer/dataloaders/segmentation/dataset.py index e66a2c651..0e9cebed8 100644 --- a/src/netspresso_trainer/dataloaders/segmentation/dataset.py +++ b/src/netspresso_trainer/dataloaders/segmentation/dataset.py @@ -9,7 +9,7 @@ from omegaconf import DictConfig, ListConfig from torch.utils.data import random_split -from ..base import BaseDataSampler +from ..base import BaseSampleLoader from ..utils.constants import IMG_EXTENSIONS from ..utils.misc import natural_key @@ -21,9 +21,9 @@ def as_tuple(tuple_string: str) -> Tuple: return tuple_value -class SegmentationDataSampler(BaseDataSampler): +class SegmentationSampleLoader(BaseSampleLoader): def __init__(self, conf_data, train_valid_split_ratio): - super(SegmentationDataSampler, self).__init__(conf_data, train_valid_split_ratio) + super(SegmentationSampleLoader, self).__init__(conf_data, train_valid_split_ratio) def load_data(self, split='train'): assert split in ['train', 'valid', 'test'], f"split should be either {['train', 'valid', 'test']}." From 9a79e0e37a311787aa7757564595b5228b51d88c Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 16 Apr 2024 07:26:32 +0000 Subject: [PATCH 06/91] Fix renamed import --- .../dataloaders/classification/__init__.py | 2 +- .../dataloaders/detection/__init__.py | 2 +- .../dataloaders/pose_estimation/__init__.py | 2 +- .../dataloaders/registry.py | 20 +++++++++---------- .../dataloaders/segmentation/__init__.py | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/netspresso_trainer/dataloaders/classification/__init__.py b/src/netspresso_trainer/dataloaders/classification/__init__.py index 8618218e3..e6f323ea8 100644 --- a/src/netspresso_trainer/dataloaders/classification/__init__.py +++ b/src/netspresso_trainer/dataloaders/classification/__init__.py @@ -1,3 +1,3 @@ -from .dataset import ClassficationDataSampler, classification_mix_collate_fn, classification_onehot_collate_fn +from .dataset import ClassficationSampleLoader, classification_mix_collate_fn, classification_onehot_collate_fn from .huggingface import ClassificationHFDataset from .local import ClassificationCustomDataset diff --git a/src/netspresso_trainer/dataloaders/detection/__init__.py b/src/netspresso_trainer/dataloaders/detection/__init__.py index 38587950d..309f131bc 100644 --- a/src/netspresso_trainer/dataloaders/detection/__init__.py +++ b/src/netspresso_trainer/dataloaders/detection/__init__.py @@ -1,2 +1,2 @@ -from .dataset import DetectionDataSampler, detection_collate_fn +from .dataset import DetectionSampleLoader, detection_collate_fn from .local import DetectionCustomDataset diff --git a/src/netspresso_trainer/dataloaders/pose_estimation/__init__.py b/src/netspresso_trainer/dataloaders/pose_estimation/__init__.py index fab83995e..aaba40a14 100644 --- a/src/netspresso_trainer/dataloaders/pose_estimation/__init__.py +++ b/src/netspresso_trainer/dataloaders/pose_estimation/__init__.py @@ -1,2 +1,2 @@ -from .dataset import PoseEstimationDataSampler +from .dataset import PoseEstimationSampleLoader from .local import PoseEstimationCustomDataset diff --git a/src/netspresso_trainer/dataloaders/registry.py b/src/netspresso_trainer/dataloaders/registry.py index cb7d20899..e9f34a2f3 100644 --- a/src/netspresso_trainer/dataloaders/registry.py +++ b/src/netspresso_trainer/dataloaders/registry.py @@ -1,20 +1,20 @@ from typing import Callable, Dict, Type from .augmentation.transforms import create_transform -from .base import BaseCustomDataset, BaseDataSampler, BaseHFDataset +from .base import BaseCustomDataset, BaseSampleLoader, BaseHFDataset from .classification import ( - ClassficationDataSampler, + ClassficationSampleLoader, ClassificationCustomDataset, ClassificationHFDataset, ) -from .detection import DetectionCustomDataset, DetectionDataSampler +from .detection import DetectionCustomDataset, DetectionSampleLoader from .pose_estimation import ( PoseEstimationCustomDataset, - PoseEstimationDataSampler, + PoseEstimationSampleLoader, ) from .segmentation import ( SegmentationCustomDataset, - SegmentationDataSampler, + SegmentationSampleLoader, SegmentationHFDataset, ) @@ -32,9 +32,9 @@ 'segmentation': SegmentationHFDataset } -DATA_SAMPLER: Dict[str, Type[BaseDataSampler]] = { - 'classification': ClassficationDataSampler, - 'segmentation': SegmentationDataSampler, - 'detection': DetectionDataSampler, - 'pose_estimation': PoseEstimationDataSampler, +DATA_SAMPLER: Dict[str, Type[BaseSampleLoader]] = { + 'classification': ClassficationSampleLoader, + 'segmentation': SegmentationSampleLoader, + 'detection': DetectionSampleLoader, + 'pose_estimation': PoseEstimationSampleLoader, } diff --git a/src/netspresso_trainer/dataloaders/segmentation/__init__.py b/src/netspresso_trainer/dataloaders/segmentation/__init__.py index 9d73a0300..4687c4f54 100644 --- a/src/netspresso_trainer/dataloaders/segmentation/__init__.py +++ b/src/netspresso_trainer/dataloaders/segmentation/__init__.py @@ -1,3 +1,3 @@ -from .dataset import SegmentationDataSampler +from .dataset import SegmentationSampleLoader from .huggingface import SegmentationHFDataset from .local import SegmentationCustomDataset From 86a83b2cdf8d84c10a63fa56f43f68f69c676650 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 16 Apr 2024 07:26:56 +0000 Subject: [PATCH 07/91] Remove unuse test_with_label --- src/netspresso_trainer/dataloaders/base.py | 13 ++----------- src/netspresso_trainer/dataloaders/builder.py | 5 +---- .../dataloaders/classification/huggingface.py | 2 -- .../dataloaders/classification/local.py | 4 ++-- .../dataloaders/detection/local.py | 4 ++-- .../dataloaders/pose_estimation/local.py | 4 ++-- .../dataloaders/segmentation/huggingface.py | 2 -- .../dataloaders/segmentation/local.py | 4 ++-- 8 files changed, 11 insertions(+), 27 deletions(-) diff --git a/src/netspresso_trainer/dataloaders/base.py b/src/netspresso_trainer/dataloaders/base.py index 69007095e..71f4e829f 100644 --- a/src/netspresso_trainer/dataloaders/base.py +++ b/src/netspresso_trainer/dataloaders/base.py @@ -11,7 +11,7 @@ class BaseCustomDataset(data.Dataset): - def __init__(self, conf_data, conf_augmentation, model_name, idx_to_class, split, samples, transform, with_label, **kwargs): + def __init__(self, conf_data, conf_augmentation, model_name, idx_to_class, split, samples, transform, **kwargs): super(BaseCustomDataset, self).__init__() self.conf_data = conf_data self.conf_augmentation = conf_augmentation @@ -24,7 +24,6 @@ def __init__(self, conf_data, conf_augmentation, model_name, idx_to_class, split self._idx_to_class = idx_to_class self._num_classes = len(self._idx_to_class) self._split = split - self._with_label = with_label self.cache = False @@ -55,13 +54,10 @@ def root(self): def mode(self): return self._split - @property - def with_label(self): - return self._with_label class BaseHFDataset(data.Dataset): - def __init__(self, conf_data, conf_augmentation, model_name, root, split, transform, with_label): + def __init__(self, conf_data, conf_augmentation, model_name, root, split, transform): super(BaseHFDataset, self).__init__() self.conf_data = conf_data self.conf_augmentation = conf_augmentation @@ -69,7 +65,6 @@ def __init__(self, conf_data, conf_augmentation, model_name, root, split, transf self.transform = transform(conf_augmentation) self._root = root self._split = split - self._with_label = with_label def _load_dataset(self, root, subset_name=None, cache_dir=None): from datasets import load_dataset @@ -102,10 +97,6 @@ def root(self): def mode(self): return self._split - @property - def with_label(self): - return self._with_label - class BaseSampleLoader(ABC): def __init__(self, conf_data, train_valid_split_ratio): diff --git a/src/netspresso_trainer/dataloaders/builder.py b/src/netspresso_trainer/dataloaders/builder.py index d68c5234a..51c33ad5e 100644 --- a/src/netspresso_trainer/dataloaders/builder.py +++ b/src/netspresso_trainer/dataloaders/builder.py @@ -38,7 +38,6 @@ def build_dataset(conf_data, conf_augmentation, task: str, model_name: str, dist train_samples, valid_samples, test_samples, misc = data_sampler.load_samples() idx_to_class = misc['idx_to_class'] if 'idx_to_class' in misc else None label_value_to_idx = misc['label_value_to_idx'] if 'label_value_to_idx' in misc else None - test_with_label = misc['test_with_label'] if 'test_with_label' in misc else None train_dataset = None if train_samples is not None: @@ -58,8 +57,7 @@ def build_dataset(conf_data, conf_augmentation, task: str, model_name: str, dist if test_samples is not None: test_dataset = CUSTOM_DATASET[task]( conf_data, conf_augmentation, model_name, idx_to_class=idx_to_class, split='test', - samples=test_samples, transform=target_transform, - with_label=test_with_label, label_value_to_idx=label_value_to_idx + samples=test_samples, transform=target_transform, label_value_to_idx=label_value_to_idx ) elif data_format == 'huggingface': @@ -71,7 +69,6 @@ def build_dataset(conf_data, conf_augmentation, task: str, model_name: str, dist train_samples, valid_samples, test_samples, misc = data_sampler.load_huggingface_samples() idx_to_class = misc['idx_to_class'] if 'idx_to_class' in misc else None label_value_to_idx = misc['label_value_to_idx'] if 'label_value_to_idx' in misc else None - test_with_label = misc['test_with_label'] if 'test_with_label' in misc else None # Assumed hugging face dataset always has training split train_dataset = HUGGINGFACE_DATASET[task]( diff --git a/src/netspresso_trainer/dataloaders/classification/huggingface.py b/src/netspresso_trainer/dataloaders/classification/huggingface.py index 0a640ef96..37c15f2a3 100644 --- a/src/netspresso_trainer/dataloaders/classification/huggingface.py +++ b/src/netspresso_trainer/dataloaders/classification/huggingface.py @@ -17,7 +17,6 @@ def __init__( split, huggingface_dataset, transform=None, - with_label=True, **kwargs ): root = conf_data.metadata.repo @@ -28,7 +27,6 @@ def __init__( root, split, transform, - with_label ) # Make sure that you additionally install `requirements-data.txt` diff --git a/src/netspresso_trainer/dataloaders/classification/local.py b/src/netspresso_trainer/dataloaders/classification/local.py index 69927c2af..3ba4c9126 100644 --- a/src/netspresso_trainer/dataloaders/classification/local.py +++ b/src/netspresso_trainer/dataloaders/classification/local.py @@ -12,10 +12,10 @@ class ClassificationCustomDataset(BaseCustomDataset): def __init__(self, conf_data, conf_augmentation, model_name, idx_to_class, - split, samples, transform=None, with_label=True, **kwargs): + split, samples, transform=None, **kwargs): super(ClassificationCustomDataset, self).__init__( conf_data, conf_augmentation, model_name, idx_to_class, - split, samples, transform, with_label, **kwargs + split, samples, transform, **kwargs ) def cache_dataset(self, sampler, distributed): diff --git a/src/netspresso_trainer/dataloaders/detection/local.py b/src/netspresso_trainer/dataloaders/detection/local.py index e71221f6a..a61b70f82 100644 --- a/src/netspresso_trainer/dataloaders/detection/local.py +++ b/src/netspresso_trainer/dataloaders/detection/local.py @@ -44,10 +44,10 @@ def get_label(label_file: Path): class DetectionCustomDataset(BaseCustomDataset): def __init__(self, conf_data, conf_augmentation, model_name, idx_to_class, - split, samples, transform=None, with_label=True, **kwargs): + split, samples, transform=None, **kwargs): super(DetectionCustomDataset, self).__init__( conf_data, conf_augmentation, model_name, idx_to_class, - split, samples, transform, with_label, **kwargs + split, samples, transform, **kwargs, ) @staticmethod diff --git a/src/netspresso_trainer/dataloaders/pose_estimation/local.py b/src/netspresso_trainer/dataloaders/pose_estimation/local.py index 663f9e474..89a5c715c 100644 --- a/src/netspresso_trainer/dataloaders/pose_estimation/local.py +++ b/src/netspresso_trainer/dataloaders/pose_estimation/local.py @@ -18,10 +18,10 @@ class PoseEstimationCustomDataset(BaseCustomDataset): def __init__(self, conf_data, conf_augmentation, model_name, idx_to_class, - split, samples, transform=None, with_label=True, **kwargs): + split, samples, transform=None, **kwargs): super(PoseEstimationCustomDataset, self).__init__( conf_data, conf_augmentation, model_name, idx_to_class, - split, samples, transform, with_label, **kwargs + split, samples, transform, **kwargs ) flattened_samples = [] # label field must be filled diff --git a/src/netspresso_trainer/dataloaders/segmentation/huggingface.py b/src/netspresso_trainer/dataloaders/segmentation/huggingface.py index 08a7cb638..1b1c4d800 100644 --- a/src/netspresso_trainer/dataloaders/segmentation/huggingface.py +++ b/src/netspresso_trainer/dataloaders/segmentation/huggingface.py @@ -18,7 +18,6 @@ def __init__( split, huggingface_dataset, transform=None, - with_label=True, **kwargs ): root = conf_data.metadata.repo @@ -29,7 +28,6 @@ def __init__( root, split, transform, - with_label ) self.idx_to_class = idx_to_class diff --git a/src/netspresso_trainer/dataloaders/segmentation/local.py b/src/netspresso_trainer/dataloaders/segmentation/local.py index 83274f964..116e63dbc 100644 --- a/src/netspresso_trainer/dataloaders/segmentation/local.py +++ b/src/netspresso_trainer/dataloaders/segmentation/local.py @@ -16,10 +16,10 @@ class SegmentationCustomDataset(BaseCustomDataset): def __init__(self, conf_data, conf_augmentation, model_name, idx_to_class, - split, samples, transform=None, with_label=True, **kwargs): + split, samples, transform=None, **kwargs): super(SegmentationCustomDataset, self).__init__( conf_data, conf_augmentation, model_name, idx_to_class, - split, samples, transform, with_label, **kwargs + split, samples, transform, **kwargs ) assert "label_value_to_idx" in kwargs self.label_value_to_idx = kwargs["label_value_to_idx"] From 2d2e7042c737566755420b7879409426357a7d1b Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 16 Apr 2024 07:37:47 +0000 Subject: [PATCH 08/91] Move collate functions to util --- src/netspresso_trainer/dataloaders/builder.py | 3 +- .../dataloaders/classification/__init__.py | 2 +- .../dataloaders/classification/dataset.py | 38 ---------- .../dataloaders/detection/__init__.py | 2 +- .../dataloaders/detection/dataset.py | 33 --------- .../dataloaders/utils/collate_fn.py | 74 +++++++++++++++++++ 6 files changed, 77 insertions(+), 75 deletions(-) create mode 100644 src/netspresso_trainer/dataloaders/utils/collate_fn.py diff --git a/src/netspresso_trainer/dataloaders/builder.py b/src/netspresso_trainer/dataloaders/builder.py index 51c33ad5e..533706c4f 100644 --- a/src/netspresso_trainer/dataloaders/builder.py +++ b/src/netspresso_trainer/dataloaders/builder.py @@ -7,10 +7,9 @@ from loguru import logger from .augmentation.registry import TRANSFORM_DICT -from .classification import classification_mix_collate_fn, classification_onehot_collate_fn -from .detection import detection_collate_fn from .registry import CREATE_TRANSFORM, CUSTOM_DATASET, DATA_SAMPLER, HUGGINGFACE_DATASET from .utils.loader import create_loader +from .utils.collate_fn import classification_mix_collate_fn, classification_onehot_collate_fn, detection_collate_fn TRAIN_VALID_SPLIT_RATIO = 0.9 diff --git a/src/netspresso_trainer/dataloaders/classification/__init__.py b/src/netspresso_trainer/dataloaders/classification/__init__.py index e6f323ea8..47750ba31 100644 --- a/src/netspresso_trainer/dataloaders/classification/__init__.py +++ b/src/netspresso_trainer/dataloaders/classification/__init__.py @@ -1,3 +1,3 @@ -from .dataset import ClassficationSampleLoader, classification_mix_collate_fn, classification_onehot_collate_fn +from .dataset import ClassficationSampleLoader from .huggingface import ClassificationHFDataset from .local import ClassificationCustomDataset diff --git a/src/netspresso_trainer/dataloaders/classification/dataset.py b/src/netspresso_trainer/dataloaders/classification/dataset.py index fdb544427..d9e486e87 100644 --- a/src/netspresso_trainer/dataloaders/classification/dataset.py +++ b/src/netspresso_trainer/dataloaders/classification/dataset.py @@ -44,44 +44,6 @@ def is_file_dict(image_dir: Union[Path, str], file_or_dir_to_idx): return True -def classification_mix_collate_fn(original_batch, mix_transforms): - indices = [] - images = [] - target = [] - for data_sample in original_batch: - indices.append(data_sample[0]) - images.append(data_sample[1]) - target.append(data_sample[2]) - - indices = torch.tensor(indices, dtype=torch.long) - images = torch.stack(images, dim=0) - target = torch.tensor(target, dtype=torch.long) - - images, target = mix_transforms(images, target) - - outputs = (indices, images, target) - return outputs - - -def classification_onehot_collate_fn(original_batch, num_classes): - indices = [] - images = [] - target = [] - for data_sample in original_batch: - indices.append(data_sample[0]) - images.append(data_sample[1]) - target.append(data_sample[2]) - - indices = torch.tensor(indices, dtype=torch.long) - images = torch.stack(images, dim=0) - target = torch.tensor(target, dtype=torch.long) - if -1 not in target: - target = F.one_hot(target, num_classes=num_classes).to(dtype=images.dtype) - - outputs = (indices, images, target) - return outputs - - class ClassficationSampleLoader(BaseSampleLoader): def __init__(self, conf_data, train_valid_split_ratio): super(ClassficationSampleLoader, self).__init__(conf_data, train_valid_split_ratio) diff --git a/src/netspresso_trainer/dataloaders/detection/__init__.py b/src/netspresso_trainer/dataloaders/detection/__init__.py index 309f131bc..55c754805 100644 --- a/src/netspresso_trainer/dataloaders/detection/__init__.py +++ b/src/netspresso_trainer/dataloaders/detection/__init__.py @@ -1,2 +1,2 @@ -from .dataset import DetectionSampleLoader, detection_collate_fn +from .dataset import DetectionSampleLoader from .local import DetectionCustomDataset diff --git a/src/netspresso_trainer/dataloaders/detection/dataset.py b/src/netspresso_trainer/dataloaders/detection/dataset.py index 558cacd91..55d847acd 100644 --- a/src/netspresso_trainer/dataloaders/detection/dataset.py +++ b/src/netspresso_trainer/dataloaders/detection/dataset.py @@ -15,39 +15,6 @@ from ..utils.misc import natural_key -def detection_collate_fn(original_batch): - indices = [] - pixel_values = [] - bbox = [] - label = [] - org_shape = [] - for data_sample in original_batch: - if 'indices' in data_sample: - indices.append(data_sample['indices']) - if 'pixel_values' in data_sample: - pixel_values.append(data_sample['pixel_values']) - if 'bbox' in data_sample: - bbox.append(data_sample['bbox']) - if 'label' in data_sample: - label.append(data_sample['label']) - if 'org_shape' in data_sample: - org_shape.append(data_sample['org_shape']) - outputs = {} - if len(indices) != 0: - indices = torch.tensor(indices, dtype=torch.long) - outputs.update({'indices': indices}) - if len(pixel_values) != 0: - pixel_values = torch.stack(pixel_values, dim=0) - outputs.update({'pixel_values': pixel_values}) - if len(bbox) != 0: - outputs.update({'bbox': bbox}) - if len(label) != 0: - outputs.update({'label': label}) - if len(org_shape) != 0: - outputs.update({'org_shape': org_shape}) - - return outputs - class DetectionSampleLoader(BaseSampleLoader): def __init__(self, conf_data, train_valid_split_ratio): super(DetectionSampleLoader, self).__init__(conf_data, train_valid_split_ratio) diff --git a/src/netspresso_trainer/dataloaders/utils/collate_fn.py b/src/netspresso_trainer/dataloaders/utils/collate_fn.py new file mode 100644 index 000000000..6d7f07d07 --- /dev/null +++ b/src/netspresso_trainer/dataloaders/utils/collate_fn.py @@ -0,0 +1,74 @@ +import torch +from torch.nn import functional as F + + +def classification_mix_collate_fn(original_batch, mix_transforms): + indices = [] + images = [] + target = [] + for data_sample in original_batch: + indices.append(data_sample[0]) + images.append(data_sample[1]) + target.append(data_sample[2]) + + indices = torch.tensor(indices, dtype=torch.long) + images = torch.stack(images, dim=0) + target = torch.tensor(target, dtype=torch.long) + + images, target = mix_transforms(images, target) + + outputs = (indices, images, target) + return outputs + + +def classification_onehot_collate_fn(original_batch, num_classes): + indices = [] + images = [] + target = [] + for data_sample in original_batch: + indices.append(data_sample[0]) + images.append(data_sample[1]) + target.append(data_sample[2]) + + indices = torch.tensor(indices, dtype=torch.long) + images = torch.stack(images, dim=0) + target = torch.tensor(target, dtype=torch.long) + if -1 not in target: + target = F.one_hot(target, num_classes=num_classes).to(dtype=images.dtype) + + outputs = (indices, images, target) + return outputs + + +def detection_collate_fn(original_batch): + indices = [] + pixel_values = [] + bbox = [] + label = [] + org_shape = [] + for data_sample in original_batch: + if 'indices' in data_sample: + indices.append(data_sample['indices']) + if 'pixel_values' in data_sample: + pixel_values.append(data_sample['pixel_values']) + if 'bbox' in data_sample: + bbox.append(data_sample['bbox']) + if 'label' in data_sample: + label.append(data_sample['label']) + if 'org_shape' in data_sample: + org_shape.append(data_sample['org_shape']) + outputs = {} + if len(indices) != 0: + indices = torch.tensor(indices, dtype=torch.long) + outputs.update({'indices': indices}) + if len(pixel_values) != 0: + pixel_values = torch.stack(pixel_values, dim=0) + outputs.update({'pixel_values': pixel_values}) + if len(bbox) != 0: + outputs.update({'bbox': bbox}) + if len(label) != 0: + outputs.update({'label': label}) + if len(org_shape) != 0: + outputs.update({'org_shape': org_shape}) + + return outputs From 5a1fdff8345f3fd6c35018d97a9666ab20a7d217 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 16 Apr 2024 07:56:41 +0000 Subject: [PATCH 09/91] Compress detection data modules to one file --- .../{detection/local.py => detection.py} | 73 ++++++++++++------- .../dataloaders/detection/__init__.py | 2 - .../dataloaders/detection/coco.yaml | 11 --- .../dataloaders/detection/dataset.py | 61 ---------------- .../dataloaders/utils/misc.py | 22 ++++++ 5 files changed, 68 insertions(+), 101 deletions(-) rename src/netspresso_trainer/dataloaders/{detection/local.py => detection.py} (61%) delete mode 100644 src/netspresso_trainer/dataloaders/detection/__init__.py delete mode 100644 src/netspresso_trainer/dataloaders/detection/coco.yaml delete mode 100644 src/netspresso_trainer/dataloaders/detection/dataset.py diff --git a/src/netspresso_trainer/dataloaders/detection/local.py b/src/netspresso_trainer/dataloaders/detection.py similarity index 61% rename from src/netspresso_trainer/dataloaders/detection/local.py rename to src/netspresso_trainer/dataloaders/detection.py index a61b70f82..1acf284b3 100644 --- a/src/netspresso_trainer/dataloaders/detection/local.py +++ b/src/netspresso_trainer/dataloaders/detection.py @@ -1,44 +1,64 @@ -import os from functools import partial from multiprocessing.pool import ThreadPool +from itertools import chain from pathlib import Path -from typing import List +from typing import Dict, List, Optional, Tuple, Union import numpy as np import PIL.Image as Image import torch import torch.distributed as dist from loguru import logger -from omegaconf import OmegaConf -from ..base import BaseCustomDataset +from .base import BaseSampleLoader, BaseCustomDataset +from .utils.constants import IMG_EXTENSIONS +from .utils.misc import natural_key, get_label + + +class DetectionSampleLoader(BaseSampleLoader): + def __init__(self, conf_data, train_valid_split_ratio): + super(DetectionSampleLoader, self).__init__(conf_data, train_valid_split_ratio) + + def load_data(self, split='train'): + assert split in ['train', 'valid', 'test'], f"split should be either {['train', 'valid', 'test']}." + data_root = Path(self.conf_data.path.root) + split_dir = self.conf_data.path[split] + image_dir: Path = data_root / split_dir.image + annotation_dir: Optional[Path] = data_root / split_dir.label if split_dir.label is not None else None + images: List[str] = [] + labels: List[str] = [] + images_and_targets: List[Dict[str, str]] = [] + if annotation_dir is not None: + for ext in IMG_EXTENSIONS: + for file in chain(image_dir.glob(f'*{ext}'), image_dir.glob(f'*{ext.upper()}')): + ann_path_maybe = annotation_dir / file.with_suffix('.txt').name + if not ann_path_maybe.exists(): + continue + images.append(str(file)) + labels.append(str(ann_path_maybe)) + # TODO: get paired data from regex pattern matching (self.conf_data.path.pattern) + + images = sorted(images, key=lambda k: natural_key(k)) + labels = sorted(labels, key=lambda k: natural_key(k)) + images_and_targets.extend([{'image': str(image), 'label': str(label)} for image, label in zip(images, labels)]) -ID2LABEL_FILENAME = "id2label.json" -TEMP_COCO_LABEL_FILE = "data/detection/coco.yaml" - - -def exist_name(candidate, folder_iterable): - try: - return list(filter(lambda x: candidate[0] in x, folder_iterable))[0] - except IndexError: - return list(filter(lambda x: candidate[1] in x, folder_iterable))[0] + else: + for ext in IMG_EXTENSIONS: + images_and_targets.extend([{'image': str(file), 'label': None} + for file in chain(image_dir.glob(f'*{ext}'), image_dir.glob(f'*{ext.upper()}'))]) + images_and_targets = sorted(images_and_targets, key=lambda k: natural_key(k['image'])) + return images_and_targets -def get_label(label_file: Path): - target = Path(label_file).read_text() + def load_id_mapping(self): + return list(self.conf_data.id_mapping) - if target == '': # target label can be empty string - target_array = np.zeros((0, 5)) - else: - try: - target_array = np.array([list(map(float, box.split(' '))) for box in target.split('\n') if box.strip()]) - except ValueError as e: - print(target) - raise e + def load_class_map(self, id_mapping): + idx_to_class: Dict[int, str] = dict(enumerate(id_mapping)) + return {'idx_to_class': idx_to_class} - label, boxes = target_array[:, 0], target_array[:, 1:] - label = label[..., np.newaxis] - return label, boxes + def load_huggingface_samples(self): + raise NotImplementedError class DetectionCustomDataset(BaseCustomDataset): @@ -134,4 +154,3 @@ def pull_item(self, index): boxes = self.xywhn2xyxy(boxes_yolo, w, h) return org_img, label, boxes - diff --git a/src/netspresso_trainer/dataloaders/detection/__init__.py b/src/netspresso_trainer/dataloaders/detection/__init__.py deleted file mode 100644 index 55c754805..000000000 --- a/src/netspresso_trainer/dataloaders/detection/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .dataset import DetectionSampleLoader -from .local import DetectionCustomDataset diff --git a/src/netspresso_trainer/dataloaders/detection/coco.yaml b/src/netspresso_trainer/dataloaders/detection/coco.yaml deleted file mode 100644 index 535de5510..000000000 --- a/src/netspresso_trainer/dataloaders/detection/coco.yaml +++ /dev/null @@ -1,11 +0,0 @@ -num_classes: 80 # number of classes -names: ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', - 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', - 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', - 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', - 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', - 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', - 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', - 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', - 'hair drier', 'toothbrush'] # class names - diff --git a/src/netspresso_trainer/dataloaders/detection/dataset.py b/src/netspresso_trainer/dataloaders/detection/dataset.py deleted file mode 100644 index 55d847acd..000000000 --- a/src/netspresso_trainer/dataloaders/detection/dataset.py +++ /dev/null @@ -1,61 +0,0 @@ -import json -import os -from itertools import chain -from pathlib import Path -from typing import Dict, List, Optional, Tuple, Union - -import numpy as np -import PIL.Image as Image -import torch -from omegaconf import DictConfig -from torch.utils.data import random_split - -from ..base import BaseSampleLoader -from ..utils.constants import IMG_EXTENSIONS -from ..utils.misc import natural_key - - -class DetectionSampleLoader(BaseSampleLoader): - def __init__(self, conf_data, train_valid_split_ratio): - super(DetectionSampleLoader, self).__init__(conf_data, train_valid_split_ratio) - - def load_data(self, split='train'): - assert split in ['train', 'valid', 'test'], f"split should be either {['train', 'valid', 'test']}." - data_root = Path(self.conf_data.path.root) - split_dir = self.conf_data.path[split] - image_dir: Path = data_root / split_dir.image - annotation_dir: Optional[Path] = data_root / split_dir.label if split_dir.label is not None else None - images: List[str] = [] - labels: List[str] = [] - images_and_targets: List[Dict[str, str]] = [] - if annotation_dir is not None: - for ext in IMG_EXTENSIONS: - for file in chain(image_dir.glob(f'*{ext}'), image_dir.glob(f'*{ext.upper()}')): - ann_path_maybe = annotation_dir / file.with_suffix('.txt').name - if not ann_path_maybe.exists(): - continue - images.append(str(file)) - labels.append(str(ann_path_maybe)) - # TODO: get paired data from regex pattern matching (self.conf_data.path.pattern) - - images = sorted(images, key=lambda k: natural_key(k)) - labels = sorted(labels, key=lambda k: natural_key(k)) - images_and_targets.extend([{'image': str(image), 'label': str(label)} for image, label in zip(images, labels)]) - - else: - for ext in IMG_EXTENSIONS: - images_and_targets.extend([{'image': str(file), 'label': None} - for file in chain(image_dir.glob(f'*{ext}'), image_dir.glob(f'*{ext.upper()}'))]) - images_and_targets = sorted(images_and_targets, key=lambda k: natural_key(k['image'])) - - return images_and_targets - - def load_id_mapping(self): - return list(self.conf_data.id_mapping) - - def load_class_map(self, id_mapping): - idx_to_class: Dict[int, str] = dict(enumerate(id_mapping)) - return {'idx_to_class': idx_to_class} - - def load_huggingface_samples(self): - raise NotImplementedError diff --git a/src/netspresso_trainer/dataloaders/utils/misc.py b/src/netspresso_trainer/dataloaders/utils/misc.py index 3fb736217..e44c7f355 100644 --- a/src/netspresso_trainer/dataloaders/utils/misc.py +++ b/src/netspresso_trainer/dataloaders/utils/misc.py @@ -1,6 +1,9 @@ import json import re from itertools import repeat +from pathlib import Path + +import numpy as np def read_json(json_path): @@ -8,6 +11,7 @@ def read_json(json_path): data = json.load(f) return data + def expand_to_chs(x, n): if not isinstance(x, (tuple, list)): x = tuple(repeat(x, n)) @@ -17,6 +21,24 @@ def expand_to_chs(x, n): assert len(x) == n, 'normalization stats must match image channels' return x + def natural_key(string_): """See http://www.codinghorror.com/blog/archives/001018.html""" return [int(s) if s.isdigit() else s for s in re.split(r'(\d+)', string_.lower())] + + +def get_label(label_file: Path): + target = Path(label_file).read_text() + + if target == '': # target label can be empty string + target_array = np.zeros((0, 5)) + else: + try: + target_array = np.array([list(map(float, box.split(' '))) for box in target.split('\n') if box.strip()]) + except ValueError as e: + print(target) + raise e + + label, boxes = target_array[:, 0], target_array[:, 1:] + label = label[..., np.newaxis] + return label, boxes From 77859e9b8cc8f32d7a39a66ae7ec6c21048303a4 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 16 Apr 2024 07:57:45 +0000 Subject: [PATCH 10/91] Rename get_label to get_detection_label --- src/netspresso_trainer/dataloaders/detection.py | 8 ++++---- src/netspresso_trainer/dataloaders/utils/misc.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/netspresso_trainer/dataloaders/detection.py b/src/netspresso_trainer/dataloaders/detection.py index 1acf284b3..904fa58cb 100644 --- a/src/netspresso_trainer/dataloaders/detection.py +++ b/src/netspresso_trainer/dataloaders/detection.py @@ -12,7 +12,7 @@ from .base import BaseSampleLoader, BaseCustomDataset from .utils.constants import IMG_EXTENSIONS -from .utils.misc import natural_key, get_label +from .utils.misc import natural_key, get_detection_label class DetectionSampleLoader(BaseSampleLoader): @@ -89,7 +89,7 @@ def _load(i, samples): image = Image.open(Path(samples[i]['image'])).convert('RGB') label = self.samples[i]['label'] if label is not None: - label = get_label(Path(label)) + label = get_detection_label(Path(label)) return i, image, label num_threads = 8 # TODO: Compute appropriate num_threads @@ -110,7 +110,7 @@ def __getitem__(self, index): else: img = Image.open(self.samples[index]['image']).convert('RGB') ann_path = Path(self.samples[index]['label']) if self.samples[index]['label'] is not None else None - ann = get_label(Path(ann_path)) if ann_path is not None else None + ann = get_detection_label(Path(ann_path)) if ann_path is not None else None w, h = img.size @@ -150,7 +150,7 @@ def pull_item(self, index): if ann_path is None: return org_img, np.zeros(0, 1), np.zeros(0, 5) - label, boxes_yolo = get_label(Path(ann_path)) + label, boxes_yolo = get_detection_label(Path(ann_path)) boxes = self.xywhn2xyxy(boxes_yolo, w, h) return org_img, label, boxes diff --git a/src/netspresso_trainer/dataloaders/utils/misc.py b/src/netspresso_trainer/dataloaders/utils/misc.py index e44c7f355..8366b7777 100644 --- a/src/netspresso_trainer/dataloaders/utils/misc.py +++ b/src/netspresso_trainer/dataloaders/utils/misc.py @@ -27,7 +27,7 @@ def natural_key(string_): return [int(s) if s.isdigit() else s for s in re.split(r'(\d+)', string_.lower())] -def get_label(label_file: Path): +def get_detection_label(label_file: Path): target = Path(label_file).read_text() if target == '': # target label can be empty string From ad7e36921df61f689cf12f7a0f17a5c43dfb960d Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 16 Apr 2024 08:14:30 +0000 Subject: [PATCH 11/91] Compress classification data modules to one file --- .../dataset.py => classification.py} | 141 +++++++++++++----- .../dataloaders/classification/__init__.py | 3 - .../dataloaders/classification/huggingface.py | 61 -------- .../dataloaders/classification/local.py | 50 ------- .../dataloaders/utils/misc.py | 28 ++++ 5 files changed, 132 insertions(+), 151 deletions(-) rename src/netspresso_trainer/dataloaders/{classification/dataset.py => classification.py} (53%) delete mode 100644 src/netspresso_trainer/dataloaders/classification/__init__.py delete mode 100644 src/netspresso_trainer/dataloaders/classification/huggingface.py delete mode 100644 src/netspresso_trainer/dataloaders/classification/local.py diff --git a/src/netspresso_trainer/dataloaders/classification/dataset.py b/src/netspresso_trainer/dataloaders/classification.py similarity index 53% rename from src/netspresso_trainer/dataloaders/classification/dataset.py rename to src/netspresso_trainer/dataloaders/classification.py index d9e486e87..61f89bd74 100644 --- a/src/netspresso_trainer/dataloaders/classification/dataset.py +++ b/src/netspresso_trainer/dataloaders/classification.py @@ -1,49 +1,20 @@ -import csv -import random -from collections import Counter +from functools import partial +from multiprocessing.pool import ThreadPool from itertools import chain from pathlib import Path from typing import Dict, List, Optional, Tuple, Union -import torch +import PIL.Image as Image +import torch.distributed as dist from loguru import logger -from omegaconf import DictConfig -from torch.nn import functional as F -from torch.utils.data import random_split -from ..base import BaseSampleLoader -from ..utils.constants import IMG_EXTENSIONS -from ..utils.misc import natural_key +from .base import BaseSampleLoader, BaseCustomDataset, BaseHFDataset +from .utils.constants import IMG_EXTENSIONS +from .utils.misc import natural_key, load_classification_class_map VALID_IMG_EXTENSIONS = IMG_EXTENSIONS + tuple((x.upper() for x in IMG_EXTENSIONS)) -def load_class_map_with_id_mapping(labels_path: Optional[Union[str, Path]]): - # Assume the `map_or_filename` is path for csv label file - assert labels_path.exists(), f"Cannot locate specified class map file {labels_path}!" - class_map_ext = labels_path.suffix.lower() - assert class_map_ext == '.csv', f"Unsupported class map file extension ({class_map_ext})!" - - with open(labels_path, newline='') as csvfile: - reader = csv.DictReader(csvfile) - file_to_idx = {row['image_id']: int(row['class']) for row in reader} - - return file_to_idx - - -def is_file_dict(image_dir: Union[Path, str], file_or_dir_to_idx): - image_dir = Path(image_dir) - candidate_name = list(file_or_dir_to_idx.keys())[0] - file_or_dir: Path = image_dir / candidate_name - if file_or_dir.exists(): - return file_or_dir.is_file() - - file_candidates = list(image_dir.glob(f"{candidate_name}.*")) - assert len(file_candidates) != 0, f"Unknown label format! Is there any something file like {file_or_dir} ?" - - return True - - class ClassficationSampleLoader(BaseSampleLoader): def __init__(self, conf_data, train_valid_split_ratio): super(ClassficationSampleLoader, self).__init__(conf_data, train_valid_split_ratio) @@ -57,7 +28,7 @@ def load_data(self, split='train'): assert split in ['train', 'valid', 'test'], f"split should be either {['train', 'valid', 'test']}" if annotation_path is not None: - file_to_idx = load_class_map_with_id_mapping(annotation_path) + file_to_idx = load_classification_class_map(annotation_path) for ext in IMG_EXTENSIONS: for file in chain(image_dir.glob(f'*{ext}'), image_dir.glob(f'*{ext.upper()}')): if file.name in file_to_idx: @@ -121,3 +92,99 @@ def load_huggingface_samples(self): train_samples = splitted_datasets['train'] valid_samples = splitted_datasets['test'] return train_samples, valid_samples, test_samples, {'idx_to_class': idx_to_class} + + +class ClassificationCustomDataset(BaseCustomDataset): + + def __init__(self, conf_data, conf_augmentation, model_name, idx_to_class, + split, samples, transform=None, **kwargs): + super(ClassificationCustomDataset, self).__init__( + conf_data, conf_augmentation, model_name, idx_to_class, + split, samples, transform, **kwargs + ) + + def cache_dataset(self, sampler, distributed): + if (not distributed) or (distributed and dist.get_rank() == 0): + logger.info(f'Caching | Loading samples of {self.mode} to memory... This can take minutes.') + + def _load(i, samples): + image = Image.open(str(samples[i]['image'])).convert('RGB') + return i, image + + num_threads = 8 # TODO: Compute appropriate num_threads + load_imgs = ThreadPool(num_threads).imap( + partial(_load, samples=self.samples), + sampler + ) + for i, image in load_imgs: + self.samples[i]['image'] = image + + self.cache = True + + def __getitem__(self, index): + img = self.samples[index]['image'] + target = self.samples[index]['label'] + if not self.cache: + img = Image.open(img).convert('RGB') + + if self.transform is not None: + out = self.transform(img) + + if target is None: + target = -1 # To be ignored at cross-entropy loss + return index, out['image'], target + + +class ClassificationHFDataset(BaseHFDataset): + + def __init__( + self, + conf_data, + conf_augmentation, + model_name, + idx_to_class, + split, + huggingface_dataset, + transform=None, + **kwargs + ): + root = conf_data.metadata.repo + super(ClassificationHFDataset, self).__init__( + conf_data, + conf_augmentation, + model_name, + root, + split, + transform, + ) + # Make sure that you additionally install `requirements-data.txt` + + self.samples = huggingface_dataset + self.idx_to_class = idx_to_class + self.class_to_idx = {v: k for k, v in self.idx_to_class.items()} + + self.image_feature_name = conf_data.metadata.features.image + self.label_feature_name = conf_data.metadata.features.label + + @property + def num_classes(self): + return len(self.idx_to_class) + + @property + def class_map(self): + return self.idx_to_class + + def __len__(self): + return self.samples.num_rows + + def __getitem__(self, index): + img: Image.Image = self.samples[index][self.image_feature_name] + target: Union[int, str] = self.samples[index][self.label_feature_name] if self.label_feature_name in self.samples[index] else None + if isinstance(target, str): + target: int = self.class_to_idx[target] + + if self.transform is not None: + out = self.transform(img) + if target is None: + target = -1 + return index, out['image'], target diff --git a/src/netspresso_trainer/dataloaders/classification/__init__.py b/src/netspresso_trainer/dataloaders/classification/__init__.py deleted file mode 100644 index 47750ba31..000000000 --- a/src/netspresso_trainer/dataloaders/classification/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .dataset import ClassficationSampleLoader -from .huggingface import ClassificationHFDataset -from .local import ClassificationCustomDataset diff --git a/src/netspresso_trainer/dataloaders/classification/huggingface.py b/src/netspresso_trainer/dataloaders/classification/huggingface.py deleted file mode 100644 index 37c15f2a3..000000000 --- a/src/netspresso_trainer/dataloaders/classification/huggingface.py +++ /dev/null @@ -1,61 +0,0 @@ -import os -from typing import Union - -import PIL.Image as Image - -from ..base import BaseHFDataset - - -class ClassificationHFDataset(BaseHFDataset): - - def __init__( - self, - conf_data, - conf_augmentation, - model_name, - idx_to_class, - split, - huggingface_dataset, - transform=None, - **kwargs - ): - root = conf_data.metadata.repo - super(ClassificationHFDataset, self).__init__( - conf_data, - conf_augmentation, - model_name, - root, - split, - transform, - ) - # Make sure that you additionally install `requirements-data.txt` - - self.samples = huggingface_dataset - self.idx_to_class = idx_to_class - self.class_to_idx = {v: k for k, v in self.idx_to_class.items()} - - self.image_feature_name = conf_data.metadata.features.image - self.label_feature_name = conf_data.metadata.features.label - - @property - def num_classes(self): - return len(self.idx_to_class) - - @property - def class_map(self): - return self.idx_to_class - - def __len__(self): - return self.samples.num_rows - - def __getitem__(self, index): - img: Image.Image = self.samples[index][self.image_feature_name] - target: Union[int, str] = self.samples[index][self.label_feature_name] if self.label_feature_name in self.samples[index] else None - if isinstance(target, str): - target: int = self.class_to_idx[target] - - if self.transform is not None: - out = self.transform(img) - if target is None: - target = -1 - return index, out['image'], target diff --git a/src/netspresso_trainer/dataloaders/classification/local.py b/src/netspresso_trainer/dataloaders/classification/local.py deleted file mode 100644 index 3ba4c9126..000000000 --- a/src/netspresso_trainer/dataloaders/classification/local.py +++ /dev/null @@ -1,50 +0,0 @@ -import os -from functools import partial -from multiprocessing.pool import ThreadPool - -import PIL.Image as Image -import torch.distributed as dist -from loguru import logger - -from ..base import BaseCustomDataset - - -class ClassificationCustomDataset(BaseCustomDataset): - - def __init__(self, conf_data, conf_augmentation, model_name, idx_to_class, - split, samples, transform=None, **kwargs): - super(ClassificationCustomDataset, self).__init__( - conf_data, conf_augmentation, model_name, idx_to_class, - split, samples, transform, **kwargs - ) - - def cache_dataset(self, sampler, distributed): - if (not distributed) or (distributed and dist.get_rank() == 0): - logger.info(f'Caching | Loading samples of {self.mode} to memory... This can take minutes.') - - def _load(i, samples): - image = Image.open(str(samples[i]['image'])).convert('RGB') - return i, image - - num_threads = 8 # TODO: Compute appropriate num_threads - load_imgs = ThreadPool(num_threads).imap( - partial(_load, samples=self.samples), - sampler - ) - for i, image in load_imgs: - self.samples[i]['image'] = image - - self.cache = True - - def __getitem__(self, index): - img = self.samples[index]['image'] - target = self.samples[index]['label'] - if not self.cache: - img = Image.open(img).convert('RGB') - - if self.transform is not None: - out = self.transform(img) - - if target is None: - target = -1 # To be ignored at cross-entropy loss - return index, out['image'], target diff --git a/src/netspresso_trainer/dataloaders/utils/misc.py b/src/netspresso_trainer/dataloaders/utils/misc.py index 8366b7777..44dc6a211 100644 --- a/src/netspresso_trainer/dataloaders/utils/misc.py +++ b/src/netspresso_trainer/dataloaders/utils/misc.py @@ -1,7 +1,9 @@ +import csv import json import re from itertools import repeat from pathlib import Path +from typing import Dict, List, Optional, Tuple, Union import numpy as np @@ -42,3 +44,29 @@ def get_detection_label(label_file: Path): label, boxes = target_array[:, 0], target_array[:, 1:] label = label[..., np.newaxis] return label, boxes + + +def load_classification_class_map(labels_path: Optional[Union[str, Path]]): + # Assume the `map_or_filename` is path for csv label file + assert labels_path.exists(), f"Cannot locate specified class map file {labels_path}!" + class_map_ext = labels_path.suffix.lower() + assert class_map_ext == '.csv', f"Unsupported class map file extension ({class_map_ext})!" + + with open(labels_path, newline='') as csvfile: + reader = csv.DictReader(csvfile) + file_to_idx = {row['image_id']: int(row['class']) for row in reader} + + return file_to_idx + + +def is_file_dict(image_dir: Union[Path, str], file_or_dir_to_idx): + image_dir = Path(image_dir) + candidate_name = list(file_or_dir_to_idx.keys())[0] + file_or_dir: Path = image_dir / candidate_name + if file_or_dir.exists(): + return file_or_dir.is_file() + + file_candidates = list(image_dir.glob(f"{candidate_name}.*")) + assert len(file_candidates) != 0, f"Unknown label format! Is there any something file like {file_or_dir} ?" + + return True From c3aca763effd37aff3b9e6b97bd58a42040709ae Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 16 Apr 2024 08:36:46 +0000 Subject: [PATCH 12/91] Compress segmentation data modules to one file --- .../dataloaders/segmentation.py | 283 ++++++++++++++++++ .../dataloaders/segmentation/__init__.py | 3 - .../dataloaders/segmentation/dataset.py | 113 ------- .../dataloaders/segmentation/huggingface.py | 96 ------ .../dataloaders/segmentation/local.py | 98 ------ .../dataloaders/utils/misc.py | 7 + 6 files changed, 290 insertions(+), 310 deletions(-) create mode 100644 src/netspresso_trainer/dataloaders/segmentation.py delete mode 100644 src/netspresso_trainer/dataloaders/segmentation/__init__.py delete mode 100644 src/netspresso_trainer/dataloaders/segmentation/dataset.py delete mode 100644 src/netspresso_trainer/dataloaders/segmentation/huggingface.py delete mode 100644 src/netspresso_trainer/dataloaders/segmentation/local.py diff --git a/src/netspresso_trainer/dataloaders/segmentation.py b/src/netspresso_trainer/dataloaders/segmentation.py new file mode 100644 index 000000000..4e366c9fc --- /dev/null +++ b/src/netspresso_trainer/dataloaders/segmentation.py @@ -0,0 +1,283 @@ +from functools import partial +from itertools import chain +from multiprocessing.pool import ThreadPool +from pathlib import Path +from typing import Dict, List, Optional, Tuple, Union, Literal + +import numpy as np +import PIL.Image as Image +import torch +import torch.distributed as dist +from omegaconf import DictConfig, ListConfig +from loguru import logger + +from .augmentation.transforms import generate_edge +from .base import BaseSampleLoader, BaseCustomDataset, BaseHFDataset +from .utils.constants import IMG_EXTENSIONS +from .utils.misc import natural_key, as_tuple + + +class SegmentationSampleLoader(BaseSampleLoader): + def __init__(self, conf_data, train_valid_split_ratio): + super(SegmentationSampleLoader, self).__init__(conf_data, train_valid_split_ratio) + + def load_data(self, split='train'): + assert split in ['train', 'valid', 'test'], f"split should be either {['train', 'valid', 'test']}." + data_root = Path(self.conf_data.path.root) + split_dir = self.conf_data.path[split] + image_dir: Path = data_root / split_dir.image + annotation_dir: Optional[Path] = data_root / split_dir.label if split_dir.label is not None else None + images: List[str] = [] + labels: List[str] = [] + images_and_targets: List[Dict[str, str]] = [] + if annotation_dir is not None: + for ext in IMG_EXTENSIONS: + images.extend([str(file) for file in chain(image_dir.glob(f'*{ext}'), image_dir.glob(f'*{ext.upper()}'))]) + # TODO: get paired data from regex pattern matching (conf_data.path.pattern) + labels.extend([str(file) for file in chain(annotation_dir.glob(f'*{ext}'), annotation_dir.glob(f'*{ext.upper()}'))]) + + images = sorted(images, key=lambda k: natural_key(k)) + labels = sorted(labels, key=lambda k: natural_key(k)) + images_and_targets.extend([{'image': str(image), 'label': str(label)} for image, label in zip(images, labels)]) + + else: + for ext in IMG_EXTENSIONS: + images_and_targets.extend([{'image': str(file), 'label': None} + for file in chain(image_dir.glob(f'*{ext}'), image_dir.glob(f'*{ext.upper()}'))]) + images_and_targets = sorted(images_and_targets, key=lambda k: natural_key(k['image'])) + + return images_and_targets + + def load_id_mapping(self): + return self.conf_data.id_mapping + + def load_class_map(self, id_mapping): + if isinstance(id_mapping, ListConfig): + assert isinstance(id_mapping[0], str), f"Unknown type for class name! {type(id_mapping[0])}" + idx_to_class: Dict[int, str] = dict(enumerate(id_mapping)) + label_value_to_idx = {k: k for k in idx_to_class} + return idx_to_class, label_value_to_idx + + idx_to_class: Dict[int, str] = {} + label_value_to_idx: Dict[Union[int, Tuple], int] = {} + for class_idx, (label_value, class_name) in enumerate(id_mapping.items()): + assert isinstance(class_name, str), "You need to format id_mapping with key for class_index, value for class_name." + if isinstance(label_value, (int, tuple)): + idx_to_class[class_idx] = class_name + label_value_to_idx[label_value] = class_idx + continue + + # Check tuple string + assert isinstance(label_value, str) and label_value.strip().startswith("(") and label_value.strip().endswith(")"), \ + f"Unknown type for color index! Should be one of (int, tuple-style str, tuple)... but {type(label_value)}" + label_value_tuple: Tuple[int, int, int] = as_tuple(label_value) + idx_to_class[class_idx] = class_name + label_value_to_idx[label_value_tuple] = class_idx + + return {'idx_to_class': idx_to_class, 'label_value_to_idx': label_value_to_idx} + + def load_huggingface_samples(self): + from datasets import load_dataset + + cache_dir = self.conf_data.metadata.custom_cache_dir + root = self.conf_data.metadata.repo + subset_name = self.conf_data.metadata.subset + if cache_dir is not None: + cache_dir = Path(cache_dir) + Path(cache_dir).mkdir(exist_ok=True, parents=True) + total_dataset = load_dataset(root, name=subset_name, cache_dir=cache_dir) + + assert isinstance(self.conf_data.id_mapping, (ListConfig, DictConfig)) + + misc = self.load_class_map(id_mapping=self.conf_data.id_mapping) + + exists_valid = 'validation' in total_dataset + exists_test = 'test' in total_dataset + + train_samples = total_dataset['train'] + valid_samples = None + if exists_valid: + valid_samples = total_dataset['validation'] + test_samples = None + if exists_test: + test_samples = total_dataset['test'] + + if not exists_valid: + splitted_datasets = train_samples.train_test_split(test_size=(1 - self.train_valid_split_ratio)) + train_samples = splitted_datasets['train'] + valid_samples = splitted_datasets['test'] + return train_samples, valid_samples, test_samples, misc + + +class SegmentationCustomDataset(BaseCustomDataset): + + def __init__(self, conf_data, conf_augmentation, model_name, idx_to_class, + split, samples, transform=None, **kwargs): + super(SegmentationCustomDataset, self).__init__( + conf_data, conf_augmentation, model_name, idx_to_class, + split, samples, transform, **kwargs + ) + assert "label_value_to_idx" in kwargs + self.label_value_to_idx = kwargs["label_value_to_idx"] + + self.label_image_mode: Literal['RGB', 'L', 'P'] = str(conf_data.label_image_mode).upper() \ + if conf_data.label_image_mode is not None else 'L' + + def cache_dataset(self, sampler, distributed): + if (not distributed) or (distributed and dist.get_rank() == 0): + logger.info(f'Caching | Loading samples of {self.mode} to memory... This can take minutes.') + + def _load(i, samples): + image = Image.open(Path(samples[i]['image'])).convert('RGB') + label = self.samples[i]['label'] + if label is not None: + label = Image.open(Path(label)).convert(self.label_image_mode) + return i, image, label + + num_threads = 8 # TODO: Compute appropriate num_threads + load_imgs = ThreadPool(num_threads).imap( + partial(_load, samples=self.samples), + sampler + ) + for i, image, label in load_imgs: + self.samples[i]['image'] = image + self.samples[i]['label'] = label + + self.cache = True + + def __getitem__(self, index): + if self.cache: + img = self.samples[index]['image'] + label = self.samples[index]['label'] + else: + img_path = self.samples[index]['image'] + ann_path = self.samples[index]['label'] + img = Image.open(Path(img_path)).convert('RGB') + label = Image.open(Path(ann_path)).convert(self.label_image_mode) if ann_path is not None else None + + w, h = img.size + + outputs = {} + outputs.update({'indices': index}) + if label is None: + out = self.transform(image=img) + outputs.update({'pixel_values': out['image'], 'org_shape': (h, w)}) + return outputs + + + label_array = np.array(label) + label_array = label_array[..., np.newaxis] if label_array.ndim == 2 else label_array + # if self.conf_augmentation.reduce_zero_label: + # label = reduce_label(np.array(label)) + + mask = np.zeros((label.size[1], label.size[0]), dtype=np.uint8) + for label_value in self.label_value_to_idx: + class_mask = (label_array == np.array(label_value)).all(axis=-1) + mask[class_mask] = self.label_value_to_idx[label_value] + + mask = Image.fromarray(mask, mode='L') # single mode array (PIL.Image) compatbile with torchvision transform API + + if 'pidnet' in self.model_name: + edge = generate_edge(np.array(mask)) + out = self.transform(image=img, mask=mask, edge=edge) + outputs.update({'pixel_values': out['image'], 'labels': out['mask'], 'edges': out['edge'].float()}) + else: + out = self.transform(image=img, mask=mask) + outputs.update({'pixel_values': out['image'], 'labels': out['mask']}) + + if self._split in ['train', 'training']: + return outputs + + assert self._split in ['val', 'valid', 'test'] + # outputs.update({'org_img': org_img, 'org_shape': (h, w)}) # TODO: return org_img with batch_size > 1 + outputs.update({'org_shape': (h, w)}) + return outputs + + +class SegmentationHFDataset(BaseHFDataset): + + def __init__( + self, + conf_data, + conf_augmentation, + model_name, + idx_to_class, + split, + huggingface_dataset, + transform=None, + **kwargs + ): + root = conf_data.metadata.repo + super(SegmentationHFDataset, self).__init__( + conf_data, + conf_augmentation, + model_name, + root, + split, + transform, + ) + + self.idx_to_class = idx_to_class + self.samples = huggingface_dataset + + assert "label_value_to_idx" in kwargs + self.label_value_to_idx = kwargs["label_value_to_idx"] + + self.label_image_mode: Literal['RGB', 'L', 'P'] = str(conf_data.label_image_mode).upper() \ + if conf_data.label_image_mode is not None else 'L' + + self.image_feature_name = conf_data.metadata.features.image + self.label_feature_name = conf_data.metadata.features.label + + @property + def num_classes(self): + return len(self.idx_to_class) + + @property + def class_map(self): + return self.idx_to_class + + def __len__(self): + return self.samples.num_rows + + def __getitem__(self, index): + + img_name = f"{index:06d}" + img: Image.Image = self.samples[index][self.image_feature_name] + label: Image.Image = self.samples[index][self.label_feature_name] if self.label_feature_name in self.samples[index] else None + + label_array = np.array(label.convert(self.label_image_mode)) + label_array = label_array[..., np.newaxis] if label_array.ndim == 2 else label_array + # if self.conf_augmentation.reduce_zero_label: + # label = reduce_label(np.array(label)) + + mask = np.zeros((label.size[1], label.size[0]), dtype=np.uint8) + for label_value in self.label_value_to_idx: + class_mask = (label_array == np.array(label_value)).all(axis=-1) + mask[class_mask] = self.label_value_to_idx[label_value] + mask = Image.fromarray(mask, mode='L') # single mode array (PIL.Image) compatbile with torchvision transform API + + w, h = img.size + + if label is None: + out = self.transform(image=img) + return {'pixel_values': out['image'], 'name': img_name, 'org_shape': (h, w)} + + outputs = {} + + if self.model_name == 'pidnet': + edge = generate_edge(np.array(label)) + out = self.transform(image=img, mask=mask, edge=edge) + outputs.update({'pixel_values': out['image'], 'labels': out['mask'], 'edges': out['edge'].float(), 'name': img_name}) + else: + out = self.transform(image=img, mask=mask) + outputs.update({'pixel_values': out['image'], 'labels': out['mask'], 'name': img_name}) + + outputs.update({'indices': index}) + if self._split in ['train', 'training']: + return outputs + + assert self._split in ['val', 'valid', 'test'] + # outputs.update({'org_img': org_img, 'org_shape': (h, w)}) # TODO: return org_img with batch_size > 1 + outputs.update({'org_shape': (h, w)}) + return outputs diff --git a/src/netspresso_trainer/dataloaders/segmentation/__init__.py b/src/netspresso_trainer/dataloaders/segmentation/__init__.py deleted file mode 100644 index 4687c4f54..000000000 --- a/src/netspresso_trainer/dataloaders/segmentation/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .dataset import SegmentationSampleLoader -from .huggingface import SegmentationHFDataset -from .local import SegmentationCustomDataset diff --git a/src/netspresso_trainer/dataloaders/segmentation/dataset.py b/src/netspresso_trainer/dataloaders/segmentation/dataset.py deleted file mode 100644 index 0e9cebed8..000000000 --- a/src/netspresso_trainer/dataloaders/segmentation/dataset.py +++ /dev/null @@ -1,113 +0,0 @@ -import json -import os -from itertools import chain -from pathlib import Path -from typing import Dict, List, Optional, Tuple, Union - -import numpy as np -import torch -from omegaconf import DictConfig, ListConfig -from torch.utils.data import random_split - -from ..base import BaseSampleLoader -from ..utils.constants import IMG_EXTENSIONS -from ..utils.misc import natural_key - - -def as_tuple(tuple_string: str) -> Tuple: - tuple_string = tuple_string.replace("(", "") - tuple_string = tuple_string.replace(")", "") - tuple_value = tuple(map(int, tuple_string.split(","))) - return tuple_value - - -class SegmentationSampleLoader(BaseSampleLoader): - def __init__(self, conf_data, train_valid_split_ratio): - super(SegmentationSampleLoader, self).__init__(conf_data, train_valid_split_ratio) - - def load_data(self, split='train'): - assert split in ['train', 'valid', 'test'], f"split should be either {['train', 'valid', 'test']}." - data_root = Path(self.conf_data.path.root) - split_dir = self.conf_data.path[split] - image_dir: Path = data_root / split_dir.image - annotation_dir: Optional[Path] = data_root / split_dir.label if split_dir.label is not None else None - images: List[str] = [] - labels: List[str] = [] - images_and_targets: List[Dict[str, str]] = [] - if annotation_dir is not None: - for ext in IMG_EXTENSIONS: - images.extend([str(file) for file in chain(image_dir.glob(f'*{ext}'), image_dir.glob(f'*{ext.upper()}'))]) - # TODO: get paired data from regex pattern matching (conf_data.path.pattern) - labels.extend([str(file) for file in chain(annotation_dir.glob(f'*{ext}'), annotation_dir.glob(f'*{ext.upper()}'))]) - - images = sorted(images, key=lambda k: natural_key(k)) - labels = sorted(labels, key=lambda k: natural_key(k)) - images_and_targets.extend([{'image': str(image), 'label': str(label)} for image, label in zip(images, labels)]) - - else: - for ext in IMG_EXTENSIONS: - images_and_targets.extend([{'image': str(file), 'label': None} - for file in chain(image_dir.glob(f'*{ext}'), image_dir.glob(f'*{ext.upper()}'))]) - images_and_targets = sorted(images_and_targets, key=lambda k: natural_key(k['image'])) - - return images_and_targets - - def load_id_mapping(self): - return self.conf_data.id_mapping - - def load_class_map(self, id_mapping): - if isinstance(id_mapping, ListConfig): - assert isinstance(id_mapping[0], str), f"Unknown type for class name! {type(id_mapping[0])}" - idx_to_class: Dict[int, str] = dict(enumerate(id_mapping)) - label_value_to_idx = {k: k for k in idx_to_class} - return idx_to_class, label_value_to_idx - - idx_to_class: Dict[int, str] = {} - label_value_to_idx: Dict[Union[int, Tuple], int] = {} - for class_idx, (label_value, class_name) in enumerate(id_mapping.items()): - assert isinstance(class_name, str), "You need to format id_mapping with key for class_index, value for class_name." - if isinstance(label_value, (int, tuple)): - idx_to_class[class_idx] = class_name - label_value_to_idx[label_value] = class_idx - continue - - # Check tuple string - assert isinstance(label_value, str) and label_value.strip().startswith("(") and label_value.strip().endswith(")"), \ - f"Unknown type for color index! Should be one of (int, tuple-style str, tuple)... but {type(label_value)}" - label_value_tuple: Tuple[int, int, int] = as_tuple(label_value) - idx_to_class[class_idx] = class_name - label_value_to_idx[label_value_tuple] = class_idx - - return {'idx_to_class': idx_to_class, 'label_value_to_idx': label_value_to_idx} - - def load_huggingface_samples(self): - from datasets import load_dataset - - cache_dir = self.conf_data.metadata.custom_cache_dir - root = self.conf_data.metadata.repo - subset_name = self.conf_data.metadata.subset - if cache_dir is not None: - cache_dir = Path(cache_dir) - Path(cache_dir).mkdir(exist_ok=True, parents=True) - total_dataset = load_dataset(root, name=subset_name, cache_dir=cache_dir) - - assert isinstance(self.conf_data.id_mapping, (ListConfig, DictConfig)) - - misc = self.load_class_map(id_mapping=self.conf_data.id_mapping) - - exists_valid = 'validation' in total_dataset - exists_test = 'test' in total_dataset - - train_samples = total_dataset['train'] - valid_samples = None - if exists_valid: - valid_samples = total_dataset['validation'] - test_samples = None - if exists_test: - test_samples = total_dataset['test'] - - if not exists_valid: - splitted_datasets = train_samples.train_test_split(test_size=(1 - self.train_valid_split_ratio)) - train_samples = splitted_datasets['train'] - valid_samples = splitted_datasets['test'] - return train_samples, valid_samples, test_samples, misc diff --git a/src/netspresso_trainer/dataloaders/segmentation/huggingface.py b/src/netspresso_trainer/dataloaders/segmentation/huggingface.py deleted file mode 100644 index 1b1c4d800..000000000 --- a/src/netspresso_trainer/dataloaders/segmentation/huggingface.py +++ /dev/null @@ -1,96 +0,0 @@ -from typing import Literal - -import numpy as np -import PIL.Image as Image - -from ..augmentation.transforms import generate_edge, reduce_label -from ..base import BaseHFDataset - - -class SegmentationHFDataset(BaseHFDataset): - - def __init__( - self, - conf_data, - conf_augmentation, - model_name, - idx_to_class, - split, - huggingface_dataset, - transform=None, - **kwargs - ): - root = conf_data.metadata.repo - super(SegmentationHFDataset, self).__init__( - conf_data, - conf_augmentation, - model_name, - root, - split, - transform, - ) - - self.idx_to_class = idx_to_class - self.samples = huggingface_dataset - - assert "label_value_to_idx" in kwargs - self.label_value_to_idx = kwargs["label_value_to_idx"] - - self.label_image_mode: Literal['RGB', 'L', 'P'] = str(conf_data.label_image_mode).upper() \ - if conf_data.label_image_mode is not None else 'L' - - self.image_feature_name = conf_data.metadata.features.image - self.label_feature_name = conf_data.metadata.features.label - - @property - def num_classes(self): - return len(self.idx_to_class) - - @property - def class_map(self): - return self.idx_to_class - - def __len__(self): - return self.samples.num_rows - - def __getitem__(self, index): - - img_name = f"{index:06d}" - img: Image.Image = self.samples[index][self.image_feature_name] - label: Image.Image = self.samples[index][self.label_feature_name] if self.label_feature_name in self.samples[index] else None - - label_array = np.array(label.convert(self.label_image_mode)) - label_array = label_array[..., np.newaxis] if label_array.ndim == 2 else label_array - # if self.conf_augmentation.reduce_zero_label: - # label = reduce_label(np.array(label)) - - mask = np.zeros((label.size[1], label.size[0]), dtype=np.uint8) - for label_value in self.label_value_to_idx: - class_mask = (label_array == np.array(label_value)).all(axis=-1) - mask[class_mask] = self.label_value_to_idx[label_value] - mask = Image.fromarray(mask, mode='L') # single mode array (PIL.Image) compatbile with torchvision transform API - - w, h = img.size - - if label is None: - out = self.transform(image=img) - return {'pixel_values': out['image'], 'name': img_name, 'org_shape': (h, w)} - - outputs = {} - - if self.model_name == 'pidnet': - edge = generate_edge(np.array(label)) - out = self.transform(image=img, mask=mask, edge=edge) - outputs.update({'pixel_values': out['image'], 'labels': out['mask'], 'edges': out['edge'].float(), 'name': img_name}) - else: - out = self.transform(image=img, mask=mask) - outputs.update({'pixel_values': out['image'], 'labels': out['mask'], 'name': img_name}) - - outputs.update({'indices': index}) - if self._split in ['train', 'training']: - return outputs - - assert self._split in ['val', 'valid', 'test'] - # outputs.update({'org_img': org_img, 'org_shape': (h, w)}) # TODO: return org_img with batch_size > 1 - outputs.update({'org_shape': (h, w)}) - return outputs diff --git a/src/netspresso_trainer/dataloaders/segmentation/local.py b/src/netspresso_trainer/dataloaders/segmentation/local.py deleted file mode 100644 index 116e63dbc..000000000 --- a/src/netspresso_trainer/dataloaders/segmentation/local.py +++ /dev/null @@ -1,98 +0,0 @@ -import os -from functools import partial -from multiprocessing.pool import ThreadPool -from pathlib import Path -from typing import Literal - -import numpy as np -import PIL.Image as Image -import torch.distributed as dist -from loguru import logger - -from ..augmentation.transforms import generate_edge, reduce_label -from ..base import BaseCustomDataset - - -class SegmentationCustomDataset(BaseCustomDataset): - - def __init__(self, conf_data, conf_augmentation, model_name, idx_to_class, - split, samples, transform=None, **kwargs): - super(SegmentationCustomDataset, self).__init__( - conf_data, conf_augmentation, model_name, idx_to_class, - split, samples, transform, **kwargs - ) - assert "label_value_to_idx" in kwargs - self.label_value_to_idx = kwargs["label_value_to_idx"] - - self.label_image_mode: Literal['RGB', 'L', 'P'] = str(conf_data.label_image_mode).upper() \ - if conf_data.label_image_mode is not None else 'L' - - def cache_dataset(self, sampler, distributed): - if (not distributed) or (distributed and dist.get_rank() == 0): - logger.info(f'Caching | Loading samples of {self.mode} to memory... This can take minutes.') - - def _load(i, samples): - image = Image.open(Path(samples[i]['image'])).convert('RGB') - label = self.samples[i]['label'] - if label is not None: - label = Image.open(Path(label)).convert(self.label_image_mode) - return i, image, label - - num_threads = 8 # TODO: Compute appropriate num_threads - load_imgs = ThreadPool(num_threads).imap( - partial(_load, samples=self.samples), - sampler - ) - for i, image, label in load_imgs: - self.samples[i]['image'] = image - self.samples[i]['label'] = label - - self.cache = True - - def __getitem__(self, index): - if self.cache: - img = self.samples[index]['image'] - label = self.samples[index]['label'] - else: - img_path = self.samples[index]['image'] - ann_path = self.samples[index]['label'] - img = Image.open(Path(img_path)).convert('RGB') - label = Image.open(Path(ann_path)).convert(self.label_image_mode) if ann_path is not None else None - - w, h = img.size - - outputs = {} - outputs.update({'indices': index}) - if label is None: - out = self.transform(image=img) - outputs.update({'pixel_values': out['image'], 'org_shape': (h, w)}) - return outputs - - - label_array = np.array(label) - label_array = label_array[..., np.newaxis] if label_array.ndim == 2 else label_array - # if self.conf_augmentation.reduce_zero_label: - # label = reduce_label(np.array(label)) - - mask = np.zeros((label.size[1], label.size[0]), dtype=np.uint8) - for label_value in self.label_value_to_idx: - class_mask = (label_array == np.array(label_value)).all(axis=-1) - mask[class_mask] = self.label_value_to_idx[label_value] - - mask = Image.fromarray(mask, mode='L') # single mode array (PIL.Image) compatbile with torchvision transform API - - if 'pidnet' in self.model_name: - edge = generate_edge(np.array(mask)) - out = self.transform(image=img, mask=mask, edge=edge) - outputs.update({'pixel_values': out['image'], 'labels': out['mask'], 'edges': out['edge'].float()}) - else: - out = self.transform(image=img, mask=mask) - outputs.update({'pixel_values': out['image'], 'labels': out['mask']}) - - if self._split in ['train', 'training']: - return outputs - - assert self._split in ['val', 'valid', 'test'] - # outputs.update({'org_img': org_img, 'org_shape': (h, w)}) # TODO: return org_img with batch_size > 1 - outputs.update({'org_shape': (h, w)}) - return outputs diff --git a/src/netspresso_trainer/dataloaders/utils/misc.py b/src/netspresso_trainer/dataloaders/utils/misc.py index 44dc6a211..f70b212c8 100644 --- a/src/netspresso_trainer/dataloaders/utils/misc.py +++ b/src/netspresso_trainer/dataloaders/utils/misc.py @@ -70,3 +70,10 @@ def is_file_dict(image_dir: Union[Path, str], file_or_dir_to_idx): assert len(file_candidates) != 0, f"Unknown label format! Is there any something file like {file_or_dir} ?" return True + + +def as_tuple(tuple_string: str) -> Tuple: + tuple_string = tuple_string.replace("(", "") + tuple_string = tuple_string.replace(")", "") + tuple_value = tuple(map(int, tuple_string.split(","))) + return tuple_value From 9a2236c930806c32c136a70311950d3de4bdd56d Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 16 Apr 2024 08:45:47 +0000 Subject: [PATCH 13/91] Compress pose estimation data modules to one file --- .../local.py => pose_estimation.py} | 57 +++++++++++++++-- .../dataloaders/pose_estimation/__init__.py | 2 - .../dataloaders/pose_estimation/dataset.py | 61 ------------------- 3 files changed, 51 insertions(+), 69 deletions(-) rename src/netspresso_trainer/dataloaders/{pose_estimation/local.py => pose_estimation.py} (60%) delete mode 100644 src/netspresso_trainer/dataloaders/pose_estimation/__init__.py delete mode 100644 src/netspresso_trainer/dataloaders/pose_estimation/dataset.py diff --git a/src/netspresso_trainer/dataloaders/pose_estimation/local.py b/src/netspresso_trainer/dataloaders/pose_estimation.py similarity index 60% rename from src/netspresso_trainer/dataloaders/pose_estimation/local.py rename to src/netspresso_trainer/dataloaders/pose_estimation.py index 89a5c715c..95bca2b71 100644 --- a/src/netspresso_trainer/dataloaders/pose_estimation/local.py +++ b/src/netspresso_trainer/dataloaders/pose_estimation.py @@ -1,18 +1,63 @@ -import os from functools import partial from multiprocessing.pool import ThreadPool +from itertools import chain from pathlib import Path -from typing import List +from typing import Dict, List, Optional, Tuple, Union -import cv2 import numpy as np import PIL.Image as Image -import torch import torch.distributed as dist from loguru import logger -from omegaconf import OmegaConf -from ..base import BaseCustomDataset +from .base import BaseSampleLoader, BaseCustomDataset +from .utils.constants import IMG_EXTENSIONS +from .utils.misc import natural_key + + +class PoseEstimationSampleLoader(BaseSampleLoader): + def __init__(self, conf_data, train_valid_split_ratio): + super(PoseEstimationSampleLoader, self).__init__(conf_data, train_valid_split_ratio) + + def load_data(self, split='train'): + assert split in ['train', 'valid', 'test'], f"split should be either {['train', 'valid', 'test']}." + data_root = Path(self.conf_data.path.root) + split_dir = self.conf_data.path[split] + image_dir: Path = data_root / split_dir.image + annotation_dir: Optional[Path] = data_root / split_dir.label if split_dir.label is not None else None + images: List[str] = [] + labels: List[str] = [] + images_and_targets: List[Dict[str, str]] = [] + if annotation_dir is not None: + for ext in IMG_EXTENSIONS: + for file in chain(image_dir.glob(f'*{ext}'), image_dir.glob(f'*{ext.upper()}')): + ann_path_maybe = annotation_dir / file.with_suffix('.txt').name + if not ann_path_maybe.exists(): + continue + images.append(str(file)) + labels.append(str(ann_path_maybe)) + # TODO: get paired data from regex pattern matching (self.conf_data.path.pattern) + + images = sorted(images, key=lambda k: natural_key(k)) + labels = sorted(labels, key=lambda k: natural_key(k)) + images_and_targets.extend([{'image': str(image), 'label': str(label)} for image, label in zip(images, labels)]) + + else: + for ext in IMG_EXTENSIONS: + images_and_targets.extend([{'image': str(file), 'label': None} + for file in chain(image_dir.glob(f'*{ext}'), image_dir.glob(f'*{ext.upper()}'))]) + images_and_targets = sorted(images_and_targets, key=lambda k: natural_key(k['image'])) + + return images_and_targets + + def load_id_mapping(self): + return list(self.conf_data.id_mapping) + + def load_class_map(self, id_mapping): + idx_to_class: Dict[int, str] = dict(enumerate(id_mapping)) + return {'idx_to_class': idx_to_class} + + def load_huggingface_samples(self): + raise NotImplementedError class PoseEstimationCustomDataset(BaseCustomDataset): diff --git a/src/netspresso_trainer/dataloaders/pose_estimation/__init__.py b/src/netspresso_trainer/dataloaders/pose_estimation/__init__.py deleted file mode 100644 index aaba40a14..000000000 --- a/src/netspresso_trainer/dataloaders/pose_estimation/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .dataset import PoseEstimationSampleLoader -from .local import PoseEstimationCustomDataset diff --git a/src/netspresso_trainer/dataloaders/pose_estimation/dataset.py b/src/netspresso_trainer/dataloaders/pose_estimation/dataset.py deleted file mode 100644 index cacb8c3b7..000000000 --- a/src/netspresso_trainer/dataloaders/pose_estimation/dataset.py +++ /dev/null @@ -1,61 +0,0 @@ -import json -import os -from itertools import chain -from pathlib import Path -from typing import Dict, List, Optional, Tuple, Union - -import numpy as np -import PIL.Image as Image -import torch -from omegaconf import DictConfig -from torch.utils.data import random_split - -from ..base import BaseSampleLoader -from ..utils.constants import IMG_EXTENSIONS -from ..utils.misc import natural_key - - -class PoseEstimationSampleLoader(BaseSampleLoader): - def __init__(self, conf_data, train_valid_split_ratio): - super(PoseEstimationSampleLoader, self).__init__(conf_data, train_valid_split_ratio) - - def load_data(self, split='train'): - assert split in ['train', 'valid', 'test'], f"split should be either {['train', 'valid', 'test']}." - data_root = Path(self.conf_data.path.root) - split_dir = self.conf_data.path[split] - image_dir: Path = data_root / split_dir.image - annotation_dir: Optional[Path] = data_root / split_dir.label if split_dir.label is not None else None - images: List[str] = [] - labels: List[str] = [] - images_and_targets: List[Dict[str, str]] = [] - if annotation_dir is not None: - for ext in IMG_EXTENSIONS: - for file in chain(image_dir.glob(f'*{ext}'), image_dir.glob(f'*{ext.upper()}')): - ann_path_maybe = annotation_dir / file.with_suffix('.txt').name - if not ann_path_maybe.exists(): - continue - images.append(str(file)) - labels.append(str(ann_path_maybe)) - # TODO: get paired data from regex pattern matching (self.conf_data.path.pattern) - - images = sorted(images, key=lambda k: natural_key(k)) - labels = sorted(labels, key=lambda k: natural_key(k)) - images_and_targets.extend([{'image': str(image), 'label': str(label)} for image, label in zip(images, labels)]) - - else: - for ext in IMG_EXTENSIONS: - images_and_targets.extend([{'image': str(file), 'label': None} - for file in chain(image_dir.glob(f'*{ext}'), image_dir.glob(f'*{ext.upper()}'))]) - images_and_targets = sorted(images_and_targets, key=lambda k: natural_key(k['image'])) - - return images_and_targets - - def load_id_mapping(self): - return list(self.conf_data.id_mapping) - - def load_class_map(self, id_mapping): - idx_to_class: Dict[int, str] = dict(enumerate(id_mapping)) - return {'idx_to_class': idx_to_class} - - def load_huggingface_samples(self): - raise NotImplementedError From 5b6e7adf88948887f5a3e371a07f09af85e25b63 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 16 Apr 2024 08:49:45 +0000 Subject: [PATCH 14/91] Remove unused --- src/netspresso_trainer/dataloaders/augmentation/README.md | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 src/netspresso_trainer/dataloaders/augmentation/README.md diff --git a/src/netspresso_trainer/dataloaders/augmentation/README.md b/src/netspresso_trainer/dataloaders/augmentation/README.md deleted file mode 100644 index ae87e0273..000000000 --- a/src/netspresso_trainer/dataloaders/augmentation/README.md +++ /dev/null @@ -1,3 +0,0 @@ -### Example image - -[astronaut.jpg](./astronaut.jpg) from https://github.com/pytorch/vision/blob/main/gallery/assets/astronaut.jpg From 65fd06967cecef573a400277b64252e3c6f77929 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 16 Apr 2024 09:09:01 +0000 Subject: [PATCH 15/91] Add dataset check in start and end of build_dataset --- src/netspresso_trainer/dataloaders/builder.py | 64 ++++++++++++++++++- src/netspresso_trainer/evaluator_common.py | 6 +- src/netspresso_trainer/inferencer_common.py | 6 +- src/netspresso_trainer/trainer_common.py | 8 +-- 4 files changed, 65 insertions(+), 19 deletions(-) diff --git a/src/netspresso_trainer/dataloaders/builder.py b/src/netspresso_trainer/dataloaders/builder.py index 533706c4f..924ae96d7 100644 --- a/src/netspresso_trainer/dataloaders/builder.py +++ b/src/netspresso_trainer/dataloaders/builder.py @@ -1,9 +1,11 @@ import os from functools import partial from pathlib import Path -from typing import Dict, List, Optional, Type, Union +from typing import Dict, Literal, List, Optional, Type, Union +from omegaconf import DictConfig import torch.distributed as dist +import torch.utils.data as data from loguru import logger from .augmentation.registry import TRANSFORM_DICT @@ -13,7 +15,64 @@ TRAIN_VALID_SPLIT_RATIO = 0.9 -def build_dataset(conf_data, conf_augmentation, task: str, model_name: str, distributed: bool): + +def dataset_mode_check(conf_data: DictConfig, mode: Literal['train', 'test']): + if mode == 'train': + if conf_data.path.test.image: + logger.info('For training, test split of dataset is not needed. This field will be ignored.') + conf_data.path.test.image = None + conf_data.path.test.label = None + + elif mode == 'test': + if conf_data.path.train.image: + logger.info('For test (evaluation or inference), train split of dataset is not needed. This field will be ignored.') + conf_data.path.train.image = None + conf_data.path.train.label = None + + if conf_data.path.valid.image: + logger.info('For test (evaluation or inference), valid split of dataset is not needed. This field will be ignored.') + conf_data.path.valid.image = None + conf_data.path.valid.label = None + + else: + raise ValueError(f"mode of build_dataset cannot be {mode}. Must be one of ['train', 'test'].") + + +def loaded_dataset_check( + conf_data: DictConfig, + train_dataset: data.Dataset, + valid_dataset: data.Dataset, + test_dataset: data.Dataset, + distributed: bool, + mode: Literal['train', 'test'] +): + if mode == 'train': + assert train_dataset is not None, "For training, train split of dataset must be provided." + if not distributed or dist.get_rank() == 0: + logger.info(f"Summary | Dataset: <{conf_data.name}> (with {conf_data.format} format)") + logger.info(f"Summary | Training dataset: {len(train_dataset)} sample(s)") + if valid_dataset is not None: + logger.info(f"Summary | Validation dataset: {len(valid_dataset)} sample(s)") + + elif mode == 'test': + assert test_dataset is not None, "For test, test split of dataset must be provided." + if not distributed or dist.get_rank() == 0: + logger.info(f"Summary | Dataset: <{conf_data.name}> (with {conf_data.format} format)") + logger.info(f"Summary | Test dataset: {len(test_dataset)} sample(s)") + + else: + raise ValueError(f"mode of build_dataset cannot be {mode}. Must be one of ['train', 'test'].") + + +def build_dataset( + conf_data: DictConfig, + conf_augmentation: DictConfig, + task: str, + model_name: str, + distributed: bool, + mode: Literal['train', 'test'], +): + dataset_mode_check(conf_data=conf_data, mode=mode) if not distributed or dist.get_rank() == 0: logger.info('-'*40) @@ -89,6 +148,7 @@ def build_dataset(conf_data, conf_augmentation, task: str, model_name: str, dist huggingface_dataset=test_samples, transform=target_transform, label_value_to_idx=label_value_to_idx ) + loaded_dataset_check(conf_data, train_dataset, valid_dataset, test_dataset, mode) return train_dataset, valid_dataset, test_dataset diff --git a/src/netspresso_trainer/evaluator_common.py b/src/netspresso_trainer/evaluator_common.py index ee14e9abc..d89944a65 100644 --- a/src/netspresso_trainer/evaluator_common.py +++ b/src/netspresso_trainer/evaluator_common.py @@ -41,11 +41,7 @@ def evaluation_common( conf.model.single_task_model = single_task_model # Build dataloader - _, _, test_dataset = build_dataset(conf.data, conf.augmentation, task, model_name, distributed=distributed) - assert test_dataset is not None, "For evaluation, valid split of dataset must be provided." - if not distributed or dist.get_rank() == 0: - logger.info(f"Summary | Dataset: <{conf.data.name}> (with {conf.data.format} format)") - logger.info(f"Summary | Validation dataset: {len(test_dataset)} sample(s)") + _, _, test_dataset = build_dataset(conf.data, conf.augmentation, task, model_name, distributed=distributed, mode='test') if conf.distributed and conf.rank == 0: torch.distributed.barrier() diff --git a/src/netspresso_trainer/inferencer_common.py b/src/netspresso_trainer/inferencer_common.py index 2ac9c347a..7c226863c 100644 --- a/src/netspresso_trainer/inferencer_common.py +++ b/src/netspresso_trainer/inferencer_common.py @@ -45,11 +45,7 @@ def inference_common( conf.model.single_task_model = single_task_model # Build dataloader - _, _, test_dataset = build_dataset(conf.data, conf.augmentation, task, model_name, distributed=distributed) - assert test_dataset is not None, "For inference, test split of dataset must be provided." - if not distributed or dist.get_rank() == 0: - logger.info(f"Summary | Dataset: <{conf.data.name}> (with {conf.data.format} format)") - logger.info(f"Summary | Test dataset: {len(test_dataset)} sample(s)") + _, _, test_dataset = build_dataset(conf.data, conf.augmentation, task, model_name, distributed=distributed, mode='test') if conf.distributed and conf.rank == 0: torch.distributed.barrier() diff --git a/src/netspresso_trainer/trainer_common.py b/src/netspresso_trainer/trainer_common.py index 69bd72240..85e78e9d4 100644 --- a/src/netspresso_trainer/trainer_common.py +++ b/src/netspresso_trainer/trainer_common.py @@ -42,13 +42,7 @@ def train_common( conf.model.single_task_model = single_task_model # Build dataloaders - train_dataset, valid_dataset, _ = build_dataset(conf.data, conf.augmentation, task, model_name, distributed=distributed) - assert train_dataset is not None, "For training, train split of dataset must be provided." - if not distributed or dist.get_rank() == 0: - logger.info(f"Summary | Dataset: <{conf.data.name}> (with {conf.data.format} format)") - logger.info(f"Summary | Training dataset: {len(train_dataset)} sample(s)") - if valid_dataset is not None: - logger.info(f"Summary | Validation dataset: {len(valid_dataset)} sample(s)") + train_dataset, valid_dataset, _ = build_dataset(conf.data, conf.augmentation, task, model_name, distributed=distributed, mode='train') # TODO: Temporarily set batch_size in train_dataset for RandomResize. This better to be removed later. train_dataset.batch_size = conf.environment.batch_size From 8d7d823be01d0150b40cfd14e9a4628714b775fe Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 16 Apr 2024 09:17:06 +0000 Subject: [PATCH 16/91] Fix missed parameter --- src/netspresso_trainer/dataloaders/builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/netspresso_trainer/dataloaders/builder.py b/src/netspresso_trainer/dataloaders/builder.py index 924ae96d7..4061ff318 100644 --- a/src/netspresso_trainer/dataloaders/builder.py +++ b/src/netspresso_trainer/dataloaders/builder.py @@ -148,7 +148,7 @@ def build_dataset( huggingface_dataset=test_samples, transform=target_transform, label_value_to_idx=label_value_to_idx ) - loaded_dataset_check(conf_data, train_dataset, valid_dataset, test_dataset, mode) + loaded_dataset_check(conf_data, train_dataset, valid_dataset, test_dataset, distributed, mode) return train_dataset, valid_dataset, test_dataset From e9a93843bd74a4c0e69b9bc1783605b8c76bb849 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 16 Apr 2024 09:22:49 +0000 Subject: [PATCH 17/91] Checkout dataset length --- src/netspresso_trainer/dataloaders/builder.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/netspresso_trainer/dataloaders/builder.py b/src/netspresso_trainer/dataloaders/builder.py index 4061ff318..24b3744f3 100644 --- a/src/netspresso_trainer/dataloaders/builder.py +++ b/src/netspresso_trainer/dataloaders/builder.py @@ -53,12 +53,14 @@ def loaded_dataset_check( logger.info(f"Summary | Training dataset: {len(train_dataset)} sample(s)") if valid_dataset is not None: logger.info(f"Summary | Validation dataset: {len(valid_dataset)} sample(s)") + assert len(train_dataset) > 0, "Training dataset has no samples. Please check your dataset path." elif mode == 'test': assert test_dataset is not None, "For test, test split of dataset must be provided." if not distributed or dist.get_rank() == 0: logger.info(f"Summary | Dataset: <{conf_data.name}> (with {conf_data.format} format)") logger.info(f"Summary | Test dataset: {len(test_dataset)} sample(s)") + assert len(test_dataset) > 0, "Test dataset has no samples. Please check your dataset path." else: raise ValueError(f"mode of build_dataset cannot be {mode}. Must be one of ['train', 'test'].") From ef28560e1431d32f15b486ddd11297c0d518b438 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 16 Apr 2024 09:23:23 +0000 Subject: [PATCH 18/91] logger print before check --- src/netspresso_trainer/dataloaders/builder.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/netspresso_trainer/dataloaders/builder.py b/src/netspresso_trainer/dataloaders/builder.py index 24b3744f3..5c7564bef 100644 --- a/src/netspresso_trainer/dataloaders/builder.py +++ b/src/netspresso_trainer/dataloaders/builder.py @@ -74,12 +74,12 @@ def build_dataset( distributed: bool, mode: Literal['train', 'test'], ): - dataset_mode_check(conf_data=conf_data, mode=mode) - if not distributed or dist.get_rank() == 0: logger.info('-'*40) logger.info("Loading data...") + dataset_mode_check(conf_data=conf_data, mode=mode) + task = conf_data.task assert task in DATA_SAMPLER, f"Data sampler for {task} is not yet supported!" From 96ba21bdf7fc4b2beaa3fb0625e942f6e67d773e Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 16 Apr 2024 09:28:20 +0000 Subject: [PATCH 19/91] Fix info to warning --- src/netspresso_trainer/dataloaders/builder.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/netspresso_trainer/dataloaders/builder.py b/src/netspresso_trainer/dataloaders/builder.py index 5c7564bef..2fd7ab42d 100644 --- a/src/netspresso_trainer/dataloaders/builder.py +++ b/src/netspresso_trainer/dataloaders/builder.py @@ -19,18 +19,18 @@ def dataset_mode_check(conf_data: DictConfig, mode: Literal['train', 'test']): if mode == 'train': if conf_data.path.test.image: - logger.info('For training, test split of dataset is not needed. This field will be ignored.') + logger.warning('For training, test split of dataset is not needed. This field will be ignored.') conf_data.path.test.image = None conf_data.path.test.label = None elif mode == 'test': if conf_data.path.train.image: - logger.info('For test (evaluation or inference), train split of dataset is not needed. This field will be ignored.') + logger.warning('For test (evaluation or inference), train split of dataset is not needed. This field will be ignored.') conf_data.path.train.image = None conf_data.path.train.label = None if conf_data.path.valid.image: - logger.info('For test (evaluation or inference), valid split of dataset is not needed. This field will be ignored.') + logger.warning('For test (evaluation or inference), valid split of dataset is not needed. This field will be ignored.') conf_data.path.valid.image = None conf_data.path.valid.label = None From c80d6b919674a143244e135da075e8f0b110bf41 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 16 Apr 2024 09:32:44 +0000 Subject: [PATCH 20/91] Check path in dataset_mode_check --- src/netspresso_trainer/dataloaders/builder.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/netspresso_trainer/dataloaders/builder.py b/src/netspresso_trainer/dataloaders/builder.py index 2fd7ab42d..e55c0ad76 100644 --- a/src/netspresso_trainer/dataloaders/builder.py +++ b/src/netspresso_trainer/dataloaders/builder.py @@ -18,12 +18,17 @@ def dataset_mode_check(conf_data: DictConfig, mode: Literal['train', 'test']): if mode == 'train': + train_check = (conf_data.path.train.image is not None) and (conf_data.path.train.label is not None) + assert train_check, "For training, train split of dataset must be provided." + if conf_data.path.test.image: logger.warning('For training, test split of dataset is not needed. This field will be ignored.') conf_data.path.test.image = None conf_data.path.test.label = None elif mode == 'test': + assert conf_data.path.train.test_dataset is not None, "For test, test split of dataset must be provided." + if conf_data.path.train.image: logger.warning('For test (evaluation or inference), train split of dataset is not needed. This field will be ignored.') conf_data.path.train.image = None @@ -47,7 +52,6 @@ def loaded_dataset_check( mode: Literal['train', 'test'] ): if mode == 'train': - assert train_dataset is not None, "For training, train split of dataset must be provided." if not distributed or dist.get_rank() == 0: logger.info(f"Summary | Dataset: <{conf_data.name}> (with {conf_data.format} format)") logger.info(f"Summary | Training dataset: {len(train_dataset)} sample(s)") @@ -56,7 +60,6 @@ def loaded_dataset_check( assert len(train_dataset) > 0, "Training dataset has no samples. Please check your dataset path." elif mode == 'test': - assert test_dataset is not None, "For test, test split of dataset must be provided." if not distributed or dist.get_rank() == 0: logger.info(f"Summary | Dataset: <{conf_data.name}> (with {conf_data.format} format)") logger.info(f"Summary | Test dataset: {len(test_dataset)} sample(s)") From 07d9b296aae71cb797baa092855c59fd39402089 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 16 Apr 2024 09:33:32 +0000 Subject: [PATCH 21/91] Rename dataset_mode_check to dataset_path_check --- src/netspresso_trainer/dataloaders/builder.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/netspresso_trainer/dataloaders/builder.py b/src/netspresso_trainer/dataloaders/builder.py index e55c0ad76..0ed89db60 100644 --- a/src/netspresso_trainer/dataloaders/builder.py +++ b/src/netspresso_trainer/dataloaders/builder.py @@ -16,7 +16,7 @@ TRAIN_VALID_SPLIT_RATIO = 0.9 -def dataset_mode_check(conf_data: DictConfig, mode: Literal['train', 'test']): +def dataset_path_check(conf_data: DictConfig, mode: Literal['train', 'test']): if mode == 'train': train_check = (conf_data.path.train.image is not None) and (conf_data.path.train.label is not None) assert train_check, "For training, train split of dataset must be provided." @@ -81,7 +81,7 @@ def build_dataset( logger.info('-'*40) logger.info("Loading data...") - dataset_mode_check(conf_data=conf_data, mode=mode) + dataset_path_check(conf_data=conf_data, mode=mode) task = conf_data.task From 0745c17c45911a141538c44687bcf839a0f4e74e Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 16 Apr 2024 09:34:56 +0000 Subject: [PATCH 22/91] Ruff fix --- src/netspresso_trainer/dataloaders/base.py | 4 ++-- src/netspresso_trainer/dataloaders/builder.py | 6 +++--- src/netspresso_trainer/dataloaders/classification.py | 8 ++++---- src/netspresso_trainer/dataloaders/detection.py | 6 +++--- src/netspresso_trainer/dataloaders/pose_estimation.py | 4 ++-- src/netspresso_trainer/dataloaders/registry.py | 4 ++-- src/netspresso_trainer/dataloaders/segmentation.py | 10 +++++----- 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/netspresso_trainer/dataloaders/base.py b/src/netspresso_trainer/dataloaders/base.py index 71f4e829f..288ce3be0 100644 --- a/src/netspresso_trainer/dataloaders/base.py +++ b/src/netspresso_trainer/dataloaders/base.py @@ -106,7 +106,7 @@ def __init__(self, conf_data, train_valid_split_ratio): @abstractmethod def load_data(self): raise NotImplementedError - + @abstractmethod def load_id_mapping(self): raise NotImplementedError @@ -114,7 +114,7 @@ def load_id_mapping(self): @abstractmethod def load_class_map(self, id_mapping): raise NotImplementedError - + def load_samples(self): assert self.conf_data.id_mapping is not None id_mapping = self.load_id_mapping() diff --git a/src/netspresso_trainer/dataloaders/builder.py b/src/netspresso_trainer/dataloaders/builder.py index 0ed89db60..b45e06107 100644 --- a/src/netspresso_trainer/dataloaders/builder.py +++ b/src/netspresso_trainer/dataloaders/builder.py @@ -1,17 +1,17 @@ import os from functools import partial from pathlib import Path -from typing import Dict, Literal, List, Optional, Type, Union +from typing import Dict, List, Literal, Optional, Type, Union -from omegaconf import DictConfig import torch.distributed as dist import torch.utils.data as data from loguru import logger +from omegaconf import DictConfig from .augmentation.registry import TRANSFORM_DICT from .registry import CREATE_TRANSFORM, CUSTOM_DATASET, DATA_SAMPLER, HUGGINGFACE_DATASET -from .utils.loader import create_loader from .utils.collate_fn import classification_mix_collate_fn, classification_onehot_collate_fn, detection_collate_fn +from .utils.loader import create_loader TRAIN_VALID_SPLIT_RATIO = 0.9 diff --git a/src/netspresso_trainer/dataloaders/classification.py b/src/netspresso_trainer/dataloaders/classification.py index 61f89bd74..8925f3c1a 100644 --- a/src/netspresso_trainer/dataloaders/classification.py +++ b/src/netspresso_trainer/dataloaders/classification.py @@ -1,6 +1,6 @@ from functools import partial -from multiprocessing.pool import ThreadPool from itertools import chain +from multiprocessing.pool import ThreadPool from pathlib import Path from typing import Dict, List, Optional, Tuple, Union @@ -8,9 +8,9 @@ import torch.distributed as dist from loguru import logger -from .base import BaseSampleLoader, BaseCustomDataset, BaseHFDataset +from .base import BaseCustomDataset, BaseHFDataset, BaseSampleLoader from .utils.constants import IMG_EXTENSIONS -from .utils.misc import natural_key, load_classification_class_map +from .utils.misc import load_classification_class_map, natural_key VALID_IMG_EXTENSIONS = IMG_EXTENSIONS + tuple((x.upper() for x in IMG_EXTENSIONS)) @@ -43,7 +43,7 @@ def load_data(self, split='train'): images_and_targets = sorted(images_and_targets, key=lambda k: natural_key(k['image'])) return images_and_targets - + def load_id_mapping(self): return list(self.conf_data.id_mapping) diff --git a/src/netspresso_trainer/dataloaders/detection.py b/src/netspresso_trainer/dataloaders/detection.py index 904fa58cb..b4289e327 100644 --- a/src/netspresso_trainer/dataloaders/detection.py +++ b/src/netspresso_trainer/dataloaders/detection.py @@ -1,6 +1,6 @@ from functools import partial -from multiprocessing.pool import ThreadPool from itertools import chain +from multiprocessing.pool import ThreadPool from pathlib import Path from typing import Dict, List, Optional, Tuple, Union @@ -10,9 +10,9 @@ import torch.distributed as dist from loguru import logger -from .base import BaseSampleLoader, BaseCustomDataset +from .base import BaseCustomDataset, BaseSampleLoader from .utils.constants import IMG_EXTENSIONS -from .utils.misc import natural_key, get_detection_label +from .utils.misc import get_detection_label, natural_key class DetectionSampleLoader(BaseSampleLoader): diff --git a/src/netspresso_trainer/dataloaders/pose_estimation.py b/src/netspresso_trainer/dataloaders/pose_estimation.py index 95bca2b71..806d4503a 100644 --- a/src/netspresso_trainer/dataloaders/pose_estimation.py +++ b/src/netspresso_trainer/dataloaders/pose_estimation.py @@ -1,6 +1,6 @@ from functools import partial -from multiprocessing.pool import ThreadPool from itertools import chain +from multiprocessing.pool import ThreadPool from pathlib import Path from typing import Dict, List, Optional, Tuple, Union @@ -9,7 +9,7 @@ import torch.distributed as dist from loguru import logger -from .base import BaseSampleLoader, BaseCustomDataset +from .base import BaseCustomDataset, BaseSampleLoader from .utils.constants import IMG_EXTENSIONS from .utils.misc import natural_key diff --git a/src/netspresso_trainer/dataloaders/registry.py b/src/netspresso_trainer/dataloaders/registry.py index e9f34a2f3..d8ab6d0ed 100644 --- a/src/netspresso_trainer/dataloaders/registry.py +++ b/src/netspresso_trainer/dataloaders/registry.py @@ -1,7 +1,7 @@ from typing import Callable, Dict, Type from .augmentation.transforms import create_transform -from .base import BaseCustomDataset, BaseSampleLoader, BaseHFDataset +from .base import BaseCustomDataset, BaseHFDataset, BaseSampleLoader from .classification import ( ClassficationSampleLoader, ClassificationCustomDataset, @@ -14,8 +14,8 @@ ) from .segmentation import ( SegmentationCustomDataset, - SegmentationSampleLoader, SegmentationHFDataset, + SegmentationSampleLoader, ) CREATE_TRANSFORM = create_transform diff --git a/src/netspresso_trainer/dataloaders/segmentation.py b/src/netspresso_trainer/dataloaders/segmentation.py index 4e366c9fc..814253df2 100644 --- a/src/netspresso_trainer/dataloaders/segmentation.py +++ b/src/netspresso_trainer/dataloaders/segmentation.py @@ -2,19 +2,19 @@ from itertools import chain from multiprocessing.pool import ThreadPool from pathlib import Path -from typing import Dict, List, Optional, Tuple, Union, Literal +from typing import Dict, List, Literal, Optional, Tuple, Union import numpy as np import PIL.Image as Image import torch import torch.distributed as dist -from omegaconf import DictConfig, ListConfig from loguru import logger +from omegaconf import DictConfig, ListConfig from .augmentation.transforms import generate_edge -from .base import BaseSampleLoader, BaseCustomDataset, BaseHFDataset +from .base import BaseCustomDataset, BaseHFDataset, BaseSampleLoader from .utils.constants import IMG_EXTENSIONS -from .utils.misc import natural_key, as_tuple +from .utils.misc import as_tuple, natural_key class SegmentationSampleLoader(BaseSampleLoader): @@ -50,7 +50,7 @@ def load_data(self, split='train'): def load_id_mapping(self): return self.conf_data.id_mapping - + def load_class_map(self, id_mapping): if isinstance(id_mapping, ListConfig): assert isinstance(id_mapping[0], str), f"Unknown type for class name! {type(id_mapping[0])}" From 70920d6f2bd4e2bebb3bf71c74f9f06bae1bbe41 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 16 Apr 2024 09:44:43 +0000 Subject: [PATCH 23/91] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 894ce6cbf..dae747d04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## New Features: -No changes to highlight. +- Add dataset validation step and refactoring data modules by `@illian01` in [PR 417](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/417) ## Bug Fixes: From eb3e312207fac001400d1cd8a4022942b33b14c5 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Wed, 17 Apr 2024 02:20:17 +0000 Subject: [PATCH 24/91] [hotfix] dataset_path_check is only for local dataset --- src/netspresso_trainer/dataloaders/builder.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/netspresso_trainer/dataloaders/builder.py b/src/netspresso_trainer/dataloaders/builder.py index b45e06107..e7c98b48f 100644 --- a/src/netspresso_trainer/dataloaders/builder.py +++ b/src/netspresso_trainer/dataloaders/builder.py @@ -57,13 +57,13 @@ def loaded_dataset_check( logger.info(f"Summary | Training dataset: {len(train_dataset)} sample(s)") if valid_dataset is not None: logger.info(f"Summary | Validation dataset: {len(valid_dataset)} sample(s)") - assert len(train_dataset) > 0, "Training dataset has no samples. Please check your dataset path." + assert len(train_dataset) > 0, "Training dataset has no samples. Please check your dataset configuration." elif mode == 'test': if not distributed or dist.get_rank() == 0: logger.info(f"Summary | Dataset: <{conf_data.name}> (with {conf_data.format} format)") logger.info(f"Summary | Test dataset: {len(test_dataset)} sample(s)") - assert len(test_dataset) > 0, "Test dataset has no samples. Please check your dataset path." + assert len(test_dataset) > 0, "Test dataset has no samples. Please check your dataset configuration." else: raise ValueError(f"mode of build_dataset cannot be {mode}. Must be one of ['train', 'test'].") @@ -81,8 +81,6 @@ def build_dataset( logger.info('-'*40) logger.info("Loading data...") - dataset_path_check(conf_data=conf_data, mode=mode) - task = conf_data.task assert task in DATA_SAMPLER, f"Data sampler for {task} is not yet supported!" @@ -95,6 +93,8 @@ def build_dataset( assert data_format in ['local', 'huggingface'], f"No such data format named {data_format} in {['local', 'huggingface']}!" if data_format == 'local': + dataset_path_check(conf_data=conf_data, mode=mode) + assert task in CUSTOM_DATASET, f"Local dataset for {task} is not yet supported!" data_sampler = DATA_SAMPLER[task](conf_data, train_valid_split_ratio=TRAIN_VALID_SPLIT_RATIO) From d0c2a48eccee1314a020bd8692f1a418c97f4bf8 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Wed, 17 Apr 2024 02:23:48 +0000 Subject: [PATCH 25/91] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dae747d04..b95dad800 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## New Features: -- Add dataset validation step and refactoring data modules by `@illian01` in [PR 417](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/417) +- Add dataset validation step and refactoring data modules by `@illian01` in [PR 417](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/417), [PR 419](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/419) ## Bug Fixes: From 9d17b74f37efb104275293ff8c10c64994b2567a Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Wed, 17 Apr 2024 03:58:57 +0000 Subject: [PATCH 26/91] Call save_summary at every end of epochs --- src/netspresso_trainer/pipelines/train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/netspresso_trainer/pipelines/train.py b/src/netspresso_trainer/pipelines/train.py index 00f2db32c..edf47582e 100644 --- a/src/netspresso_trainer/pipelines/train.py +++ b/src/netspresso_trainer/pipelines/train.py @@ -137,10 +137,10 @@ def train(self): time_for_epoch=time_for_epoch, valid_samples=valid_samples, valid_logging=with_valid_logging) + self.save_summary() if with_checkpoint_saving: assert with_valid_logging self.save_checkpoint(epoch=num_epoch) - self.save_summary() logger.info("-" * 40) self.scheduler.step() # call after reporting the current `learning_rate` From 846876f90f6137a92c5a114f2c70d21f6257eea3 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Wed, 17 Apr 2024 04:03:08 +0000 Subject: [PATCH 27/91] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b95dad800..fecdb9eaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ No changes to highlight. ## Other Changes: -No changes to highlight. +- Save training summary at every end of epochs by `@illian01` in [PR 420](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/420) # v0.2.0 From e61c62ebcbd0e04dcfed83adcec810337c1f648e Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Thu, 18 Apr 2024 01:38:54 +0000 Subject: [PATCH 28/91] Add cifar100 auto download code --- tools/open_dataset_tool/cifar100.py | 95 +++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 tools/open_dataset_tool/cifar100.py diff --git a/tools/open_dataset_tool/cifar100.py b/tools/open_dataset_tool/cifar100.py new file mode 100644 index 000000000..d14729d59 --- /dev/null +++ b/tools/open_dataset_tool/cifar100.py @@ -0,0 +1,95 @@ +import argparse +from pathlib import Path +import os +import tarfile + +import cv2 +import numpy as np +import pandas as pd +import torch +from tqdm import tqdm + +DEFAULT_DATA_DIR = './data' +DOWNLOAD_DIR = './data/auto_downloaded' +CIFAR100_URL = 'https://www.cs.toronto.edu/~kriz/cifar-100-python.tar.gz' + + +def unpickle(file): + import pickle + with open(file, 'rb') as fo: + dict = pickle.load(fo, encoding='bytes') + return dict + + +if __name__ == '__main__': + # Set argument (data directory) + parser = argparse.ArgumentParser(description="Parser for CIFAR100 dataset downloader.") + parser.add_argument('--dir', type=str, default=DEFAULT_DATA_DIR) + args = parser.parse_args() + + # Download cifar 100 dataset + os.makedirs(DOWNLOAD_DIR, exist_ok=True) + download_path = Path(DOWNLOAD_DIR) / 'cifar100.tar.gz' + if download_path.exists(): + print(f'Download path {download_path} already exists! download step is skipped.') + else: + torch.hub.download_url_to_file(CIFAR100_URL, download_path) + + # Extract tar.gz file + ap = tarfile.open(download_path) + + data_dir = Path(args.dir) / 'cifar100' + os.makedirs(data_dir, exist_ok=True) + ap.extractall(data_dir) + ap.close() + + # Read data + extracted_dir = data_dir / 'cifar-100-python' # auto-generated by ap.extractall + cifar_train = extracted_dir / 'train' + cifar_test = extracted_dir / 'test' + cifar_meta = extracted_dir / 'meta' + + cifar_train = unpickle(cifar_train) + cifar_test = unpickle(cifar_test) + cifar_meta = unpickle(cifar_meta) + + cifar_meta = cifar_meta[b'fine_label_names'] + cifar_meta = [c.decode('utf-8') for c in cifar_meta] + + # Re-format train split + train_image_dir = data_dir / 'images' / 'train' + train_label_dir = data_dir / 'labels' / 'train' + + os.makedirs(train_image_dir, exist_ok=True) + os.makedirs(train_label_dir, exist_ok=True) + + train_names = cifar_train[b'filenames'] + train_names = [n.decode('utf-8') for n in train_names] + train_images = cifar_train[b'data'] + for name, image in tqdm(zip(train_names, train_images)): + image = np.transpose(image.reshape(3, 32, 32), (1, 2, 0)) + image = image[..., ::-1] + cv2.imwrite(str(train_image_dir / name), image) + + train_labels = cifar_train[b'fine_labels'] + train_label_csv = pd.DataFrame({'image_id': train_names, 'class': train_labels}) + train_label_csv.to_csv(train_label_dir / 'cifar100_train.csv', mode='w', index=False) + + # Re-format valid split + valid_image_dir = data_dir / 'images' / 'valid' + valid_label_dir = data_dir / 'labels' / 'valid' + + os.makedirs(valid_image_dir, exist_ok=True) + os.makedirs(valid_label_dir, exist_ok=True) + + val_names = cifar_test[b'filenames'] + val_names = [n.decode('utf-8') for n in val_names] + val_images = cifar_test[b'data'] + for name, image in tqdm(zip(val_names, val_images)): + image = np.transpose(image.reshape(3, 32, 32), (1, 2, 0)) + image = image[..., ::-1] + cv2.imwrite(str(valid_image_dir / name), image) + + val_labels = cifar_test[b'fine_labels'] + val_label_csv = pd.DataFrame({'image_id': val_names, 'class': val_labels}) + val_label_csv.to_csv(valid_label_dir / 'cifar100_val.csv', mode='w', index=False) From 8b9e98bb0ac7c62d9b33cc2037ac387adfa47256 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Thu, 18 Apr 2024 10:53:56 +0000 Subject: [PATCH 29/91] Add imagenet1k extracting and reformatting code --- tools/open_dataset_tool/imagenet1k.py | 135 ++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 tools/open_dataset_tool/imagenet1k.py diff --git a/tools/open_dataset_tool/imagenet1k.py b/tools/open_dataset_tool/imagenet1k.py new file mode 100644 index 000000000..90a2cc29f --- /dev/null +++ b/tools/open_dataset_tool/imagenet1k.py @@ -0,0 +1,135 @@ +import argparse +from pathlib import Path +import os +import tarfile +import shutil + +import scipy +import cv2 +import numpy as np +import pandas as pd +import torch +from tqdm import tqdm + +DEFAULT_DATA_DIR = './data' + + +if __name__ == '__main__': + # Set argument (data directory) + parser = argparse.ArgumentParser(description="Parser for CIFAR100 dataset downloader.") + parser.add_argument('--dir', type=str, default=DEFAULT_DATA_DIR) + parser.add_argument('--train-images', type=str, dest='train_images', required=True, + help="ImageNet1K dataset cannot be downloaded automatically. Download dataset from https://www.image-net.org/ and set train path here.") + parser.add_argument('--valid-images', type=str, dest='valid_images', required=True, + help="ImageNet1K dataset cannot be downloaded automatically. Download dataset from https://www.image-net.org/ and set validation path here.") + parser.add_argument('--devkit', type=str, dest='devkit', required=True, + help="ImageNet1K dataset cannot be downloaded automatically. Download dataset from https://www.image-net.org/ and set devkit path here.") + args = parser.parse_args() + + # Set base directory + imagenet_path = Path(args.dir) / 'imagenet1k' + os.makedirs(imagenet_path, exist_ok=True) + + # Extract train split + train_image_dir = imagenet_path / 'images' / 'train' + os.makedirs(train_image_dir, exist_ok=True) + + print('Extracting training images tar file... This may take a minutes.') + tmp2extract = imagenet_path / 'tmp2extract' + os.makedirs(tmp2extract, exist_ok=True) + + ap = tarfile.open(Path(args.train_images)) + ap.extractall(tmp2extract) + ap.close() + + print('Extracting training images from each class tar file.') + tar_files = os.listdir() + for extract_file in tqdm(tar_files): + extract_file = tmp2extract / (extract_file + '.tar') + ap = tarfile.open(extract_file) + ap.extractall(train_image_dir) + ap.close() + try: + os.remove(extract_file) + except OSError as e: + print(e) + try: + shutil.rmtree(tmp2extract) + except OSError as e: + print(e) + print('Done!') + + # Extract valid split + print('Extracting valid images tar file...') + valid_image_dir = imagenet_path / 'images' / 'valid' + os.makedirs(valid_image_dir, exist_ok=True) + + ap = tarfile.open(Path(args.valid_images)) + ap.extractall(valid_image_dir) # Extract directly + ap.close() + + print('Done!') + + # Extract meta files + print('Extracting meta data ...') + ap = tarfile.open(Path(args.devkit)) + ap.extractall(imagenet_path) + ap.close() + + devkit_extracted = imagenet_path / 'ILSVRC2012_devkit_t12' + meta = devkit_extracted / 'data' / 'meta.mat' + + mat = scipy.io.loadmat(meta) + + cls_to_name = {} + id_to_cls = {} + for row in mat['synsets']: + row = row[0] + + cls_name = row[2].item().split(',')[0] + cls_id = row[1].item() + cls_num = row[0].item() - 1 + + cls_to_name[cls_num] = cls_name + id_to_cls[cls_id] = cls_num + + try: + shutil.rmtree(devkit_extracted) + except OSError as e: + print(e) + print('Done!') + + # Build train label csv file + print('Building train label csv file ...') + train_label_dir = imagenet_path / 'labels' / 'train' + os.makedirs(train_label_dir, exist_ok=True) + + samples = os.listdir(imagenet_path / 'images' / 'train') + labels = [] + for sample in samples: + labels.append(id_to_cls[sample.split('_')[0]]) + + train_csv = pd.DataFrame({'image_id': samples, 'class': labels}) + train_csv.to_csv(train_label_dir / 'imagenet_train.csv', mode='w', index=False) + print('Done!') + + # Build valid label csv file + print('Building valid label csv file ...') + valid_label_dir = imagenet_path / 'labels' / 'valid' + os.makedirs(valid_label_dir, exist_ok=True) + + with open(devkit_extracted / 'data' / 'ILSVRC2012_validation_ground_truth.txt') as f: + labels = f.readlines() + labels = [int(l.strip()) - 1 for l in labels] + f.close() + valid_csv = pd.DataFrame({'image_id': sorted(os.listdir(imagenet_path / 'images' / 'valid')), 'class': labels}) + valid_csv.to_csv(valid_label_dir / 'imagenet_valid.csv', mode='w', index=False) + print('Done!') + + # Build id_mapping + print('Building id_mapping ...') + id_mapping = [cls_to_name[i] for i in range(1000)] + with open(imagenet_path / 'id_mapping', 'w') as f: + f.write('\n'.join(id_mapping)) + f.close() + print('Done!') From a9225d5019983bd0aabc10475bb3cdd755867d4c Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Thu, 18 Apr 2024 11:01:07 +0000 Subject: [PATCH 30/91] Fix path error --- tools/open_dataset_tool/imagenet1k.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/open_dataset_tool/imagenet1k.py b/tools/open_dataset_tool/imagenet1k.py index 90a2cc29f..1129d2c5b 100644 --- a/tools/open_dataset_tool/imagenet1k.py +++ b/tools/open_dataset_tool/imagenet1k.py @@ -43,7 +43,7 @@ ap.close() print('Extracting training images from each class tar file.') - tar_files = os.listdir() + tar_files = os.listdir(tmp2extract) for extract_file in tqdm(tar_files): extract_file = tmp2extract / (extract_file + '.tar') ap = tarfile.open(extract_file) From ddfce9ac70a3c90cd77309f7b7d75fcd38ce62dc Mon Sep 17 00:00:00 2001 From: yooeun chun Date: Fri, 19 Apr 2024 14:37:29 +0900 Subject: [PATCH 31/91] refactor: postprocessors/register.py -> registry.py --- src/netspresso_trainer/postprocessors/builder.py | 2 +- .../postprocessors/{register.py => registry.py} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/netspresso_trainer/postprocessors/{register.py => registry.py} (100%) diff --git a/src/netspresso_trainer/postprocessors/builder.py b/src/netspresso_trainer/postprocessors/builder.py index abb93ffe5..c205b0ea0 100644 --- a/src/netspresso_trainer/postprocessors/builder.py +++ b/src/netspresso_trainer/postprocessors/builder.py @@ -1,4 +1,4 @@ -from .register import POSTPROCESSOR_DICT +from .registry import POSTPROCESSOR_DICT def build_postprocessor(task: str, conf_model): diff --git a/src/netspresso_trainer/postprocessors/register.py b/src/netspresso_trainer/postprocessors/registry.py similarity index 100% rename from src/netspresso_trainer/postprocessors/register.py rename to src/netspresso_trainer/postprocessors/registry.py From 2d93095dcf4aae498afb9d54d2e07cac28ee418b Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Fri, 19 Apr 2024 05:56:52 +0000 Subject: [PATCH 32/91] Fix errors --- tools/open_dataset_tool/imagenet1k.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/open_dataset_tool/imagenet1k.py b/tools/open_dataset_tool/imagenet1k.py index 1129d2c5b..512bb5491 100644 --- a/tools/open_dataset_tool/imagenet1k.py +++ b/tools/open_dataset_tool/imagenet1k.py @@ -45,7 +45,7 @@ print('Extracting training images from each class tar file.') tar_files = os.listdir(tmp2extract) for extract_file in tqdm(tar_files): - extract_file = tmp2extract / (extract_file + '.tar') + extract_file = tmp2extract / (extract_file) ap = tarfile.open(extract_file) ap.extractall(train_image_dir) ap.close() @@ -92,11 +92,6 @@ cls_to_name[cls_num] = cls_name id_to_cls[cls_id] = cls_num - - try: - shutil.rmtree(devkit_extracted) - except OSError as e: - print(e) print('Done!') # Build train label csv file @@ -126,6 +121,11 @@ valid_csv.to_csv(valid_label_dir / 'imagenet_valid.csv', mode='w', index=False) print('Done!') + try: + shutil.rmtree(devkit_extracted) + except OSError as e: + print(e) + # Build id_mapping print('Building id_mapping ...') id_mapping = [cls_to_name[i] for i in range(1000)] From 25fa792a014c82ee4ef8eb92248705921fa31158 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Fri, 19 Apr 2024 06:26:08 +0000 Subject: [PATCH 33/91] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fecdb9eaa..85d60d11b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ No changes to highlight. ## Other Changes: - Save training summary at every end of epochs by `@illian01` in [PR 420](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/420) +- Refacotring: rename postprocessors/register.py to registry.py by `@aychun` in [PR 424](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/424) # v0.2.0 From 4212e8100348b38627e4243830764483adc4c29b Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Fri, 19 Apr 2024 06:57:32 +0000 Subject: [PATCH 34/91] Change download path --- tools/open_dataset_tool/cifar100.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/open_dataset_tool/cifar100.py b/tools/open_dataset_tool/cifar100.py index d14729d59..430dd05bc 100644 --- a/tools/open_dataset_tool/cifar100.py +++ b/tools/open_dataset_tool/cifar100.py @@ -10,7 +10,7 @@ from tqdm import tqdm DEFAULT_DATA_DIR = './data' -DOWNLOAD_DIR = './data/auto_downloaded' +DOWNLOAD_DIR = './data/download' CIFAR100_URL = 'https://www.cs.toronto.edu/~kriz/cifar-100-python.tar.gz' From 3ad5ff9b9b559727d0df1f988532e7a5d3500e7d Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Fri, 19 Apr 2024 16:31:14 +0000 Subject: [PATCH 35/91] Add coco2017 auto download code --- tools/open_dataset_tool/cooco2017.py | 159 +++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 tools/open_dataset_tool/cooco2017.py diff --git a/tools/open_dataset_tool/cooco2017.py b/tools/open_dataset_tool/cooco2017.py new file mode 100644 index 000000000..a7fe78f87 --- /dev/null +++ b/tools/open_dataset_tool/cooco2017.py @@ -0,0 +1,159 @@ +import argparse +from pathlib import Path +import os +import tarfile +import shutil +import json + +import scipy +import cv2 +import numpy as np +import pandas as pd +import torch +from tqdm import tqdm + +DEFAULT_DATA_DIR = './data' +DOWNLOAD_DIR = './data/download' +TRAIN_IMAGES_URL = 'http://images.cocodataset.org/zips/train2017.zip' +VALID_IMAGES_URL = 'http://images.cocodataset.org/zips/val2017.zip' +ANNOTATION_URL = 'http://images.cocodataset.org/annotations/annotations_trainval2017.zip' +CLASS80_NAME_TO_LABEL = {'person': 0, 'bicycle': 1, 'car': 2, 'motorcycle': 3, 'airplane': 4, 'bus': 5, 'train': 6, 'truck': 7, 'boat': 8, 'traffic light': 9, 'fire hydrant': 10, 'stop sign': 11, 'parking meter': 12, 'bench': 13, 'bird': 14, 'cat': 15, 'dog': 16, 'horse': 17, 'sheep': 18, 'cow': 19, 'elephant': 20, 'bear': 21, 'zebra': 22, 'giraffe': 23, 'backpack': 24, 'umbrella': 25, 'handbag': 26, 'tie': 27, 'suitcase': 28, 'frisbee': 29, 'skis': 30, 'snowboard': 31, 'sports ball': 32, 'kite': 33, 'baseball bat': 34, 'baseball glove': 35, 'skateboard': 36, 'surfboard': 37, 'tennis racket': 38, 'bottle': 39, 'wine glass': 40, 'cup': 41, 'fork': 42, 'knife': 43, 'spoon': 44, 'bowl': 45, 'banana': 46, 'apple': 47, 'sandwich': 48, 'orange': 49, 'broccoli': 50, 'carrot': 51, 'hot dog': 52, 'pizza': 53, 'donut': 54, 'cake': 55, 'chair': 56, 'couch': 57, 'potted plant': 58, 'bed': 59, 'dining table': 60, 'toilet': 61, 'tv': 62, 'laptop': 63, 'mouse': 64, 'remote': 65, 'keyboard': 66, 'cell phone': 67, 'microwave': 68, 'oven': 69, 'toaster': 70, 'sink': 71, 'refrigerator': 72, 'book': 73, 'clock': 74, 'vase': 75, 'scissors': 76, 'teddy bear': 77, 'hair drier': 78, 'toothbrush': 79} + + +def txtywh2cxcywh(top_left_x, top_left_y, width, height): + cx = top_left_x + (width / 2) + cy = top_left_y + (height / 2) + w = width + h = height + return cx, cy, w, h + + +if __name__ == '__main__': + # Set argument (data directory) + parser = argparse.ArgumentParser(description="Parser for coco2017 dataset downloader.") + parser.add_argument('--dir', type=str, default=DEFAULT_DATA_DIR) + args = parser.parse_args() + + # Download coco2017 dataset + os.makedirs(DOWNLOAD_DIR, exist_ok=True) + + train_images_download_path = Path(DOWNLOAD_DIR) / 'train2017.zip' + if train_images_download_path.exists(): + print(f'Download path {train_images_download_path} already exists! download step is skipped.') + else: + torch.hub.download_url_to_file(TRAIN_IMAGES_URL, train_images_download_path) + + valid_images_download_path = Path(DOWNLOAD_DIR) / 'val2017.zip' + if valid_images_download_path.exists(): + print(f'Download path {valid_images_download_path} already exists! download step is skipped.') + else: + torch.hub.download_url_to_file(VALID_IMAGES_URL, valid_images_download_path) + + ann_download_path = Path(DOWNLOAD_DIR) / 'annotaions_trainval2017.zip' + if ann_download_path.exists(): + print(f'Download path {ann_download_path} already exists! download step is skipped.') + else: + torch.hub.download_url_to_file(ANNOTATION_URL, ann_download_path) + + coco2017_path = Path(args.dir) / 'coco2017' + os.makedirs(coco2017_path, exist_ok=True) + + # Unzip train images + print('Unzip training images zip file ...') + train_images_dir = coco2017_path / 'images' + shutil.unpack_archive(train_images_download_path, train_images_dir, "zip") + print('Rename train2017 to train') + os.rename(train_images_dir / 'train2017', train_images_dir / 'train') + print('Done!') + + # Unzip valid images + print('Unzip training images zip file ...') + valid_images_dir = coco2017_path / 'images' + shutil.unpack_archive(valid_images_download_path, valid_images_dir, "zip") + print('Rename val2017 to valid') + os.rename(train_images_dir / 'val2017', train_images_dir / 'valid') + print('Done!') + + # Unzip annotation zip file + print('Unzip annotation zip file ...') + shutil.unpack_archive(ann_download_path, coco2017_path, "zip") + print('Done!') + + # Reformat train annotaion to yolo format + # TODO: Support yolo format and leave yolo format as optional + print('Building train labels ...') + train_annotation_path = coco2017_path / 'annotations' / 'instances_train2017.json' + train_label_dir = coco2017_path / 'labels' / 'train' + os.makedirs(train_label_dir, exist_ok=True) + + with open(train_annotation_path) as f: + train_ann_json = json.load(f) + + category = train_ann_json['categories'] + CLASS91_LABEL_TO_NAME = {} + for item in category: + CLASS91_LABEL_TO_NAME[item['id']] = item['name'] + + train_annotations = {image_info['id']: [image_info['file_name']] for image_info in train_ann_json['images']} + for ann in tqdm(train_ann_json['annotations']): + image_id = ann['image_id'] + + category_id = ann['category_id'] + label = CLASS80_NAME_TO_LABEL[CLASS91_LABEL_TO_NAME[category_id]] + + # TODO: Support various box type e.g. xyxy + top_left_x, top_left_y, width, height = ann['bbox'] + cx, cy, w, h = txtywh2cxcywh(top_left_x, top_left_y, width, height) + + instance = [label, cx, cy, w, h] + train_annotations[image_id].append(instance) + + for image_id, info in tqdm(train_annotations.items()): + file_name = info[0] + + texts = '' + if len(info) != 1: + for line in info[1:]: + texts += f'{line[0]} {line[1]} {line[2]} {line[3]} {line[4]}\n' + + with open((train_label_dir / file_name).with_suffix('.txt'), 'w') as f: + f.write(texts) + + # Reformat valid annotaion to yolo format + print('Building valid labels ...') + valid_annotation_path = coco2017_path / 'annotations' / 'instances_val2017.json' + valid_label_dir = coco2017_path / 'labels' / 'valid' + os.makedirs(valid_label_dir, exist_ok=True) + + with open(valid_annotation_path) as f: + valid_ann_json = json.load(f) + + valid_annotations = {image_info['id']: [image_info['file_name']] for image_info in valid_ann_json['images']} + for ann in tqdm(valid_ann_json['annotations']): + image_id = ann['image_id'] + + category_id = ann['category_id'] + label = CLASS80_NAME_TO_LABEL[CLASS91_LABEL_TO_NAME[category_id]] + + # TODO: Support various box type e.g. xyxy + top_left_x, top_left_y, width, height = ann['bbox'] + cx, cy, w, h = txtywh2cxcywh(top_left_x, top_left_y, width, height) + + instance = [label, cx, cy, w, h] + valid_annotations[image_id].append(instance) + + for image_id, info in tqdm(valid_annotations.items()): + file_name = info[0] + + texts = '' + if len(info) != 1: + for line in info[1:]: + texts += f'{line[0]} {line[1]} {line[2]} {line[3]} {line[4]}\n' + + with open((valid_label_dir / file_name).with_suffix('.txt'), 'w') as f: + f.write(texts) + + try: + shutil.rmtree(coco2017_path / 'annotations') + except OSError as e: + print(e) \ No newline at end of file From 8e53971b570b25aa631b5c9a4ead65dfdf9c03f8 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Sun, 21 Apr 2024 13:24:38 +0000 Subject: [PATCH 36/91] Add voc2012 auto download code --- tools/open_dataset_tool/voc2012_seg.py | 85 ++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 tools/open_dataset_tool/voc2012_seg.py diff --git a/tools/open_dataset_tool/voc2012_seg.py b/tools/open_dataset_tool/voc2012_seg.py new file mode 100644 index 000000000..ea82532c2 --- /dev/null +++ b/tools/open_dataset_tool/voc2012_seg.py @@ -0,0 +1,85 @@ +import argparse +from pathlib import Path +import os +import tarfile +import shutil + +import cv2 +import numpy as np +import pandas as pd +import torch +from tqdm import tqdm + +DEFAULT_DATA_DIR = './data' +DOWNLOAD_DIR = './data/download' +VOC2012_URL = 'http://host.robots.ox.ac.uk/pascal/VOC/voc2012/VOCtrainval_11-May-2012.tar' + + +def unpickle(file): + import pickle + with open(file, 'rb') as fo: + dict = pickle.load(fo, encoding='bytes') + return dict + + +if __name__ == '__main__': + # Set argument (data directory) + parser = argparse.ArgumentParser(description="Parser for VOC 2012 dataset downloader.") + parser.add_argument('--dir', type=str, default=DEFAULT_DATA_DIR) + args = parser.parse_args() + + # Download VOC 2012 dataset + os.makedirs(DOWNLOAD_DIR, exist_ok=True) + download_path = Path(DOWNLOAD_DIR) / 'VOCtrainval_11-May-2012.tar' + if download_path.exists(): + print(f'Download path {download_path} already exists! download step is skipped.') + else: + torch.hub.download_url_to_file(VOC2012_URL, download_path) + + # Extract tar file + ap = tarfile.open(download_path) + + voc2012_path = Path(args.dir) / 'voc2012_seg' + os.makedirs(voc2012_path, exist_ok=True) + ap.extractall(voc2012_path) + ap.close() + + img_src = voc2012_path / 'VOCdevkit' / 'VOC2012' / 'JPEGImages' + label_src = voc2012_path / 'VOCdevkit' / 'VOC2012' / 'SegmentationClass' + + # Get train sample list + train_samples = voc2012_path / 'VOCdevkit' / 'VOC2012' / 'ImageSets' / 'Segmentation' / 'train.txt' + with open(train_samples, 'r') as f: + train_samples = f.readlines() + train_samples = [sample.strip() for sample in train_samples] + + # Move train images and masks + train_image_dir = voc2012_path / 'images' / 'train' + train_label_dir = voc2012_path / 'labels' / 'train' + + os.makedirs(train_image_dir) + os.makedirs(train_label_dir) + for sample in train_samples: + shutil.move(img_src / (sample + '.jpg'), train_image_dir / (sample + '.jpg')) + shutil.move(label_src / (sample + '.png'), train_label_dir / (sample + '.png')) + + # Get valid sample list + valid_samples = voc2012_path / 'VOCdevkit' / 'VOC2012' / 'ImageSets' / 'Segmentation' / 'val.txt' + with open(valid_samples, 'r') as f: + valid_samples = f.readlines() + valid_samples = [sample.strip() for sample in valid_samples] + + # Move valid images and masks + valid_image_dir = voc2012_path / 'images' / 'valid' + valid_label_dir = voc2012_path / 'labels' / 'valid' + + os.makedirs(valid_image_dir) + os.makedirs(valid_label_dir) + for sample in valid_samples: + shutil.move(img_src / (sample + '.jpg'), valid_image_dir / (sample + '.jpg')) + shutil.move(label_src / (sample + '.png'), valid_label_dir / (sample + '.png')) + + try: + shutil.rmtree(voc2012_path / 'VOCdevkit') + except OSError as e: + print(e) From 8de8801c6a25ac6c63bea5374621d5efcc54ff86 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Sun, 21 Apr 2024 13:46:02 +0000 Subject: [PATCH 37/91] Name typo... --- tools/open_dataset_tool/{cooco2017.py => coco2017.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tools/open_dataset_tool/{cooco2017.py => coco2017.py} (100%) diff --git a/tools/open_dataset_tool/cooco2017.py b/tools/open_dataset_tool/coco2017.py similarity index 100% rename from tools/open_dataset_tool/cooco2017.py rename to tools/open_dataset_tool/coco2017.py From 86cf1736bc06943b9b94116b149bb719f512adea Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Sun, 21 Apr 2024 14:21:24 +0000 Subject: [PATCH 38/91] Add open_dataset_tool README --- tools/open_dataset_tool/README.md | 57 +++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 tools/open_dataset_tool/README.md diff --git a/tools/open_dataset_tool/README.md b/tools/open_dataset_tool/README.md new file mode 100644 index 000000000..7042cf6d2 --- /dev/null +++ b/tools/open_dataset_tool/README.md @@ -0,0 +1,57 @@ +## Dataset preparation (Local) + +If you are interested in utilizing well-known open datasets, you can exploit them by following the instructions. + +### Image classification + +
+CIFAR100 + +Simply run `cifar100.py` python file with your dataset directory as an argument. + +CIFAR100 dataset will be automatically downloaded to `./data/download`. After executing scripts, you can use [pre-defined configuration](https://github.com/Nota-NetsPresso/netspresso-trainer/blob/dev/config/data/cifar100.yaml). + +```bash +python ./tools/open_dataset_tool/cifar100.py --dir ./data +``` +
+ +
+ImageNet1K + +ImageNet1K dataset cannot be automatically downloaded. You should download dataset from [ImageNet](https://www.image-net.org/) website, and place downloaded files into `./data/download`. + +And, run `imagenet1k.py` python file with your dataset directorty and downloaded files path as arguments. After executing scripts, you can use [pre-defined configuration](). + +```bash +python ./tools/open_dataset_tool/imagenet1k.py --dir ./data --train-images ./data/download/ILSVRC2012_img_train.tar --valid-images ./data/download/ILSVRC2012_img_val.tar --devkit ./data/download/ILSVRC2012_devkit_t12.tar.gz +``` +
+ +### Semantic segmentation + +
+PascalVOC 2012 + +Simply run `voc2012_seg.py` python file with your dataset directory as an argument. + +PascalVOC 2012 dataset will be automatically downloaded to `./data/download`. After executing scripts, you can use [pre-defined configuration](https://github.com/Nota-NetsPresso/netspresso-trainer/blob/dev/config/data/voc12.yaml). + +```bash +python ./tools/open_dataset_tool/voc2012_seg.py --dir ./data +``` +
+ +### Object detection + +
+COCO 2017 + +Simply run `coco2017.py` python file with your dataset directory as an argument. + +COCO 2017 dataset will be automatically downloaded to `./data/download`. After executing scripts, you can use [pre-defined configuration](https://github.com/Nota-NetsPresso/netspresso-trainer/blob/dev/config/data/coco2017.yaml). + +```bash +python ./tools/open_dataset_tool/coco2017.py --dir ./data +``` +
From df9e47c369d5957753fc399870052f896b42a648 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Sun, 21 Apr 2024 15:01:50 +0000 Subject: [PATCH 39/91] Remove extracted dirs and change label dir --- tools/open_dataset_tool/cifar100.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/open_dataset_tool/cifar100.py b/tools/open_dataset_tool/cifar100.py index 430dd05bc..0f6aa2863 100644 --- a/tools/open_dataset_tool/cifar100.py +++ b/tools/open_dataset_tool/cifar100.py @@ -2,6 +2,7 @@ from pathlib import Path import os import tarfile +import shutil import cv2 import numpy as np @@ -58,7 +59,7 @@ def unpickle(file): # Re-format train split train_image_dir = data_dir / 'images' / 'train' - train_label_dir = data_dir / 'labels' / 'train' + train_label_dir = data_dir / 'labels' os.makedirs(train_image_dir, exist_ok=True) os.makedirs(train_label_dir, exist_ok=True) @@ -77,7 +78,7 @@ def unpickle(file): # Re-format valid split valid_image_dir = data_dir / 'images' / 'valid' - valid_label_dir = data_dir / 'labels' / 'valid' + valid_label_dir = data_dir / 'labels' os.makedirs(valid_image_dir, exist_ok=True) os.makedirs(valid_label_dir, exist_ok=True) @@ -93,3 +94,8 @@ def unpickle(file): val_labels = cifar_test[b'fine_labels'] val_label_csv = pd.DataFrame({'image_id': val_names, 'class': val_labels}) val_label_csv.to_csv(valid_label_dir / 'cifar100_val.csv', mode='w', index=False) + + try: + shutil.rmtree(extracted_dir) + except OSError as e: + print(e) \ No newline at end of file From 02a5f0a91987f4e4d94d427423ddd696143352c2 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Sun, 21 Apr 2024 15:02:01 +0000 Subject: [PATCH 40/91] Update cifar100.yaml --- config/data/cifar100.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 config/data/cifar100.yaml diff --git a/config/data/cifar100.yaml b/config/data/cifar100.yaml new file mode 100644 index 000000000..eac052e62 --- /dev/null +++ b/config/data/cifar100.yaml @@ -0,0 +1,16 @@ +data: + name: cifar100 + task: classification + format: local + path: + root: ./data/cifar-100 # dataset root + train: + image: images/train # directory for training images + label: labels/cifar100_train.csv # label for training labels + valid: + image: images/valid # directory for valid images + label: labels/cifar100_val.csv # durectory for valid labels + test: + image: ~ + label: ~ + id_mapping: ['apple', 'aquarium_fish', 'baby', 'bear', 'beaver', 'bed', 'bee', 'beetle', 'bicycle', 'bottle', 'bowl', 'boy', 'bridge', 'bus', 'butterfly', 'camel', 'can', 'castle', 'caterpillar', 'cattle', 'chair', 'chimpanzee', 'clock', 'cloud', 'cockroach', 'couch', 'crab', 'crocodile', 'cup', 'dinosaur', 'dolphin', 'elephant', 'flatfish', 'forest', 'fox', 'girl', 'hamster', 'house', 'kangaroo', 'keyboard', 'lamp', 'lawn_mower', 'leopard', 'lion', 'lizard', 'lobster', 'man', 'maple_tree', 'motorcycle', 'mountain', 'mouse', 'mushroom', 'oak_tree', 'orange', 'orchid', 'otter', 'palm_tree', 'pear', 'pickup_truck', 'pine_tree', 'plain', 'plate', 'poppy', 'porcupine', 'possum', 'rabbit', 'raccoon', 'ray', 'road', 'rocket', 'rose', 'sea', 'seal', 'shark', 'shrew', 'skunk', 'skyscraper', 'snail', 'snake', 'spider', 'squirrel', 'streetcar', 'sunflower', 'sweet_pepper', 'table', 'tank', 'telephone', 'television', 'tiger', 'tractor', 'train', 'trout', 'tulip', 'turtle', 'wardrobe', 'whale', 'willow_tree', 'wolf', 'woman', 'worm'] \ No newline at end of file From d92cd790182a11c5afc33454edb066c0d710a099 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Sun, 21 Apr 2024 15:05:51 +0000 Subject: [PATCH 41/91] Add id_mapping save --- tools/open_dataset_tool/cifar100.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/open_dataset_tool/cifar100.py b/tools/open_dataset_tool/cifar100.py index 0f6aa2863..4d99b97e8 100644 --- a/tools/open_dataset_tool/cifar100.py +++ b/tools/open_dataset_tool/cifar100.py @@ -13,6 +13,7 @@ DEFAULT_DATA_DIR = './data' DOWNLOAD_DIR = './data/download' CIFAR100_URL = 'https://www.cs.toronto.edu/~kriz/cifar-100-python.tar.gz' +CIFAR100_CLASSES = ['apple', 'aquarium_fish', 'baby', 'bear', 'beaver', 'bed', 'bee', 'beetle', 'bicycle', 'bottle', 'bowl', 'boy', 'bridge', 'bus', 'butterfly', 'camel', 'can', 'castle', 'caterpillar', 'cattle', 'chair', 'chimpanzee', 'clock', 'cloud', 'cockroach', 'couch', 'crab', 'crocodile', 'cup', 'dinosaur', 'dolphin', 'elephant', 'flatfish', 'forest', 'fox', 'girl', 'hamster', 'house', 'kangaroo', 'keyboard', 'lamp', 'lawn_mower', 'leopard', 'lion', 'lizard', 'lobster', 'man', 'maple_tree', 'motorcycle', 'mountain', 'mouse', 'mushroom', 'oak_tree', 'orange', 'orchid', 'otter', 'palm_tree', 'pear', 'pickup_truck', 'pine_tree', 'plain', 'plate', 'poppy', 'porcupine', 'possum', 'rabbit', 'raccoon', 'ray', 'road', 'rocket', 'rose', 'sea', 'seal', 'shark', 'shrew', 'skunk', 'skyscraper', 'snail', 'snake', 'spider', 'squirrel', 'streetcar', 'sunflower', 'sweet_pepper', 'table', 'tank', 'telephone', 'television', 'tiger', 'tractor', 'train', 'trout', 'tulip', 'turtle', 'wardrobe', 'whale', 'willow_tree', 'wolf', 'woman', 'worm'] def unpickle(file): @@ -95,6 +96,12 @@ def unpickle(file): val_label_csv = pd.DataFrame({'image_id': val_names, 'class': val_labels}) val_label_csv.to_csv(valid_label_dir / 'cifar100_val.csv', mode='w', index=False) + # Build id_mapping + id_mapping = CIFAR100_CLASSES + with open(data_dir / 'id_mapping', 'w') as f: + f.write('\n'.join(id_mapping)) + f.close() + try: shutil.rmtree(extracted_dir) except OSError as e: From 57d95df0a3db43854d34408d84db7576d22e83f6 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Sun, 21 Apr 2024 15:11:39 +0000 Subject: [PATCH 42/91] Update scipy --- requirements-optional.txt | 3 ++- tools/open_dataset_tool/README.md | 2 ++ tools/open_dataset_tool/coco2017.py | 1 - 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/requirements-optional.txt b/requirements-optional.txt index d1e4c25c0..acc7ee812 100644 --- a/requirements-optional.txt +++ b/requirements-optional.txt @@ -4,4 +4,5 @@ pandas requests albumentations pymongo[srv]==3.8.0 -torch_tb_profiler \ No newline at end of file +torch_tb_profiler +scipy \ No newline at end of file diff --git a/tools/open_dataset_tool/README.md b/tools/open_dataset_tool/README.md index 7042cf6d2..f0f59a9ae 100644 --- a/tools/open_dataset_tool/README.md +++ b/tools/open_dataset_tool/README.md @@ -23,6 +23,8 @@ ImageNet1K dataset cannot be automatically downloaded. You should download datas And, run `imagenet1k.py` python file with your dataset directorty and downloaded files path as arguments. After executing scripts, you can use [pre-defined configuration](). +*(`imagenet1k.py` needs scipy library which is in [requirements-optional.txt](https://github.com/Nota-NetsPresso/netspresso-trainer/blob/dev/requirements-optional.txt))* + ```bash python ./tools/open_dataset_tool/imagenet1k.py --dir ./data --train-images ./data/download/ILSVRC2012_img_train.tar --valid-images ./data/download/ILSVRC2012_img_val.tar --devkit ./data/download/ILSVRC2012_devkit_t12.tar.gz ``` diff --git a/tools/open_dataset_tool/coco2017.py b/tools/open_dataset_tool/coco2017.py index a7fe78f87..d3add4750 100644 --- a/tools/open_dataset_tool/coco2017.py +++ b/tools/open_dataset_tool/coco2017.py @@ -5,7 +5,6 @@ import shutil import json -import scipy import cv2 import numpy as np import pandas as pd From 3c82dddd28ad49cfc9d30667c20ecf4a9029b8a3 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Sun, 21 Apr 2024 15:13:26 +0000 Subject: [PATCH 43/91] Fix typo --- config/data/cifar100.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/data/cifar100.yaml b/config/data/cifar100.yaml index eac052e62..77fc10ea9 100644 --- a/config/data/cifar100.yaml +++ b/config/data/cifar100.yaml @@ -8,7 +8,7 @@ data: image: images/train # directory for training images label: labels/cifar100_train.csv # label for training labels valid: - image: images/valid # directory for valid images + image: images/valid # directory for valid images label: labels/cifar100_val.csv # durectory for valid labels test: image: ~ From f00296f1e3e4ba50a17286268486b6b605cc94be Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Sun, 21 Apr 2024 15:44:47 +0000 Subject: [PATCH 44/91] Update imagenet1k.yaml --- config/data/imagenet1k.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 config/data/imagenet1k.yaml diff --git a/config/data/imagenet1k.yaml b/config/data/imagenet1k.yaml new file mode 100644 index 000000000..b5809ce80 --- /dev/null +++ b/config/data/imagenet1k.yaml @@ -0,0 +1,16 @@ +data: + name: IMAGENET1K + task: classification + format: local # local, huggingface + path: + root: ./data/imagenet1k # dataset root + train: + image: images/train # directory for training images + label: labels/imagenet_train.csv # directory for training labels or csv file + valid: + image: images/valid # directory for valid images + label: labels/imagenet_valid.csv # directory for valid labels or csv file + test: + image: ~ + label: ~ + id_mapping: ['kit fox', 'English setter', 'Siberian husky', 'Australian terrier', 'English springer', 'grey whale', 'lesser panda', 'Egyptian cat', 'ibex', 'Persian cat', 'cougar', 'gazelle', 'porcupine', 'sea lion', 'malamute', 'badger', 'Great Dane', 'Walker hound', 'Welsh springer spaniel', 'whippet', 'Scottish deerhound', 'killer whale', 'mink', 'African elephant', 'Weimaraner', 'soft-coated wheaten terrier', 'Dandie Dinmont', 'red wolf', 'Old English sheepdog', 'jaguar', 'otterhound', 'bloodhound', 'Airedale', 'hyena', 'meerkat', 'giant schnauzer', 'titi', 'three-toed sloth', 'sorrel', 'black-footed ferret', 'dalmatian', 'black-and-tan coonhound', 'papillon', 'skunk', 'Staffordshire bullterrier', 'Mexican hairless', 'Bouvier des Flandres', 'weasel', 'miniature poodle', 'Cardigan', 'malinois', 'bighorn', 'fox squirrel', 'colobus', 'tiger cat', 'Lhasa', 'impala', 'coyote', 'Yorkshire terrier', 'Newfoundland', 'brown bear', 'red fox', 'Norwegian elkhound', 'Rottweiler', 'hartebeest', 'Saluki', 'grey fox', 'schipperke', 'Pekinese', 'Brabancon griffon', 'West Highland white terrier', 'Sealyham terrier', 'guenon', 'mongoose', 'indri', 'tiger', 'Irish wolfhound', 'wild boar', 'EntleBucher', 'zebra', 'ram', 'French bulldog', 'orangutan', 'basenji', 'leopard', 'Bernese mountain dog', 'Maltese dog', 'Norfolk terrier', 'toy terrier', 'vizsla', 'cairn', 'squirrel monkey', 'groenendael', 'clumber', 'Siamese cat', 'chimpanzee', 'komondor', 'Afghan hound', 'Japanese spaniel', 'proboscis monkey', 'guinea pig', 'white wolf', 'ice bear', 'gorilla', 'borzoi', 'toy poodle', 'Kerry blue terrier', 'ox', 'Scotch terrier', 'Tibetan mastiff', 'spider monkey', 'Doberman', 'Boston bull', 'Greater Swiss Mountain dog', 'Appenzeller', 'Shih-Tzu', 'Irish water spaniel', 'Pomeranian', 'Bedlington terrier', 'warthog', 'Arabian camel', 'siamang', 'miniature schnauzer', 'collie', 'golden retriever', 'Irish terrier', 'affenpinscher', 'Border collie', 'hare', 'boxer', 'silky terrier', 'beagle', 'Leonberg', 'German short-haired pointer', 'patas', 'dhole', 'baboon', 'macaque', 'Chesapeake Bay retriever', 'bull mastiff', 'kuvasz', 'capuchin', 'pug', 'curly-coated retriever', 'Norwich terrier', 'flat-coated retriever', 'hog', 'keeshond', 'Eskimo dog', 'Brittany spaniel', 'standard poodle', 'Lakeland terrier', 'snow leopard', 'Gordon setter', 'dingo', 'standard schnauzer', 'hamster', 'Tibetan terrier', 'Arctic fox', 'wire-haired fox terrier', 'basset', 'water buffalo', 'American black bear', 'Angora', 'bison', 'howler monkey', 'hippopotamus', 'chow', 'giant panda', 'American Staffordshire terrier', 'Shetland sheepdog', 'Great Pyrenees', 'Chihuahua', 'tabby', 'marmoset', 'Labrador retriever', 'Saint Bernard', 'armadillo', 'Samoyed', 'bluetick', 'redbone', 'polecat', 'marmot', 'kelpie', 'gibbon', 'llama', 'miniature pinscher', 'wood rabbit', 'Italian greyhound', 'lion', 'cocker spaniel', 'Irish setter', 'dugong', 'Indian elephant', 'beaver', 'Sussex spaniel', 'Pembroke', 'Blenheim spaniel', 'Madagascar cat', 'Rhodesian ridgeback', 'lynx', 'African hunting dog', 'langur', 'Ibizan hound', 'timber wolf', 'cheetah', 'English foxhound', 'briard', 'sloth bear', 'Border terrier', 'German shepherd', 'otter', 'koala', 'tusker', 'echidna', 'wallaby', 'platypus', 'wombat', 'revolver', 'umbrella', 'schooner', 'soccer ball', 'accordion', 'ant', 'starfish', 'chambered nautilus', 'grand piano', 'laptop', 'strawberry', 'airliner', 'warplane', 'airship', 'balloon', 'space shuttle', 'fireboat', 'gondola', 'speedboat', 'lifeboat', 'canoe', 'yawl', 'catamaran', 'trimaran', 'container ship', 'liner', 'pirate', 'aircraft carrier', 'submarine', 'wreck', 'half track', 'tank', 'missile', 'bobsled', 'dogsled', 'bicycle-built-for-two', 'mountain bike', 'freight car', 'passenger car', 'barrow', 'shopping cart', 'motor scooter', 'forklift', 'electric locomotive', 'steam locomotive', 'amphibian', 'ambulance', 'beach wagon', 'cab', 'convertible', 'jeep', 'limousine', 'minivan', 'Model T', 'racer', 'sports car', 'go-kart', 'golfcart', 'moped', 'snowplow', 'fire engine', 'garbage truck', 'pickup', 'tow truck', 'trailer truck', 'moving van', 'police van', 'recreational vehicle', 'streetcar', 'snowmobile', 'tractor', 'mobile home', 'tricycle', 'unicycle', 'horse cart', 'jinrikisha', 'oxcart', 'bassinet', 'cradle', 'crib', 'four-poster', 'bookcase', 'china cabinet', 'medicine chest', 'chiffonier', 'table lamp', 'file', 'park bench', 'barber chair', 'throne', 'folding chair', 'rocking chair', 'studio couch', 'toilet seat', 'desk', 'pool table', 'dining table', 'entertainment center', 'wardrobe', 'Granny Smith', 'orange', 'lemon', 'fig', 'pineapple', 'banana', 'jackfruit', 'custard apple', 'pomegranate', 'acorn', 'hip', 'ear', 'rapeseed', 'corn', 'buckeye', 'organ', 'upright', 'chime', 'drum', 'gong', 'maraca', 'marimba', 'steel drum', 'banjo', 'cello', 'violin', 'harp', 'acoustic guitar', 'electric guitar', 'cornet', 'French horn', 'trombone', 'harmonica', 'ocarina', 'panpipe', 'bassoon', 'oboe', 'sax', 'flute', 'daisy', "yellow lady's slipper", 'cliff', 'valley', 'alp', 'volcano', 'promontory', 'sandbar', 'coral reef', 'lakeside', 'seashore', 'geyser', 'hatchet', 'cleaver', 'letter opener', 'plane', 'power drill', 'lawn mower', 'hammer', 'corkscrew', 'can opener', 'plunger', 'screwdriver', 'shovel', 'plow', 'chain saw', 'cock', 'hen', 'ostrich', 'brambling', 'goldfinch', 'house finch', 'junco', 'indigo bunting', 'robin', 'bulbul', 'jay', 'magpie', 'chickadee', 'water ouzel', 'kite', 'bald eagle', 'vulture', 'great grey owl', 'black grouse', 'ptarmigan', 'ruffed grouse', 'prairie chicken', 'peacock', 'quail', 'partridge', 'African grey', 'macaw', 'sulphur-crested cockatoo', 'lorikeet', 'coucal', 'bee eater', 'hornbill', 'hummingbird', 'jacamar', 'toucan', 'drake', 'red-breasted merganser', 'goose', 'black swan', 'white stork', 'black stork', 'spoonbill', 'flamingo', 'American egret', 'little blue heron', 'bittern', 'crane', 'limpkin', 'American coot', 'bustard', 'ruddy turnstone', 'red-backed sandpiper', 'redshank', 'dowitcher', 'oystercatcher', 'European gallinule', 'pelican', 'king penguin', 'albatross', 'great white shark', 'tiger shark', 'hammerhead', 'electric ray', 'stingray', 'barracouta', 'coho', 'tench', 'goldfish', 'eel', 'rock beauty', 'anemone fish', 'lionfish', 'puffer', 'sturgeon', 'gar', 'loggerhead', 'leatherback turtle', 'mud turtle', 'terrapin', 'box turtle', 'banded gecko', 'common iguana', 'American chameleon', 'whiptail', 'agama', 'frilled lizard', 'alligator lizard', 'Gila monster', 'green lizard', 'African chameleon', 'Komodo dragon', 'triceratops', 'African crocodile', 'American alligator', 'thunder snake', 'ringneck snake', 'hognose snake', 'green snake', 'king snake', 'garter snake', 'water snake', 'vine snake', 'night snake', 'boa constrictor', 'rock python', 'Indian cobra', 'green mamba', 'sea snake', 'horned viper', 'diamondback', 'sidewinder', 'European fire salamander', 'common newt', 'eft', 'spotted salamander', 'axolotl', 'bullfrog', 'tree frog', 'tailed frog', 'whistle', 'wing', 'paintbrush', 'hand blower', 'oxygen mask', 'snorkel', 'loudspeaker', 'microphone', 'screen', 'mouse', 'electric fan', 'oil filter', 'strainer', 'space heater', 'stove', 'guillotine', 'barometer', 'rule', 'odometer', 'scale', 'analog clock', 'digital clock', 'wall clock', 'hourglass', 'sundial', 'parking meter', 'stopwatch', 'digital watch', 'stethoscope', 'syringe', 'magnetic compass', 'binoculars', 'projector', 'sunglasses', 'loupe', 'radio telescope', 'bow', 'cannon', 'assault rifle', 'rifle', 'projectile', 'computer keyboard', 'typewriter keyboard', 'crane', 'lighter', 'abacus', 'cash machine', 'slide rule', 'desktop computer', 'hand-held computer', 'notebook', 'web site', 'harvester', 'thresher', 'printer', 'slot', 'vending machine', 'sewing machine', 'joystick', 'switch', 'hook', 'car wheel', 'paddlewheel', 'pinwheel', "potter's wheel", 'gas pump', 'carousel', 'swing', 'reel', 'radiator', 'puck', 'hard disc', 'sunglass', 'pick', 'car mirror', 'solar dish', 'remote control', 'disk brake', 'buckle', 'hair slide', 'knot', 'combination lock', 'padlock', 'nail', 'safety pin', 'screw', 'muzzle', 'seat belt', 'ski', 'candle', "jack-o'-lantern", 'spotlight', 'torch', 'neck brace', 'pier', 'tripod', 'maypole', 'mousetrap', 'spider web', 'trilobite', 'harvestman', 'scorpion', 'black and gold garden spider', 'barn spider', 'garden spider', 'black widow', 'tarantula', 'wolf spider', 'tick', 'centipede', 'isopod', 'Dungeness crab', 'rock crab', 'fiddler crab', 'king crab', 'American lobster', 'spiny lobster', 'crayfish', 'hermit crab', 'tiger beetle', 'ladybug', 'ground beetle', 'long-horned beetle', 'leaf beetle', 'dung beetle', 'rhinoceros beetle', 'weevil', 'fly', 'bee', 'grasshopper', 'cricket', 'walking stick', 'cockroach', 'mantis', 'cicada', 'leafhopper', 'lacewing', 'dragonfly', 'damselfly', 'admiral', 'ringlet', 'monarch', 'cabbage butterfly', 'sulphur butterfly', 'lycaenid', 'jellyfish', 'sea anemone', 'brain coral', 'flatworm', 'nematode', 'conch', 'snail', 'slug', 'sea slug', 'chiton', 'sea urchin', 'sea cucumber', 'iron', 'espresso maker', 'microwave', 'Dutch oven', 'rotisserie', 'toaster', 'waffle iron', 'vacuum', 'dishwasher', 'refrigerator', 'washer', 'Crock Pot', 'frying pan', 'wok', 'caldron', 'coffeepot', 'teapot', 'spatula', 'altar', 'triumphal arch', 'patio', 'steel arch bridge', 'suspension bridge', 'viaduct', 'barn', 'greenhouse', 'palace', 'monastery', 'library', 'apiary', 'boathouse', 'church', 'mosque', 'stupa', 'planetarium', 'restaurant', 'cinema', 'home theater', 'lumbermill', 'coil', 'obelisk', 'totem pole', 'castle', 'prison', 'grocery store', 'bakery', 'barbershop', 'bookshop', 'butcher shop', 'confectionery', 'shoe shop', 'tobacco shop', 'toyshop', 'fountain', 'cliff dwelling', 'yurt', 'dock', 'brass', 'megalith', 'bannister', 'breakwater', 'dam', 'chainlink fence', 'picket fence', 'worm fence', 'stone wall', 'grille', 'sliding door', 'turnstile', 'mountain tent', 'scoreboard', 'honeycomb', 'plate rack', 'pedestal', 'beacon', 'mashed potato', 'bell pepper', 'head cabbage', 'broccoli', 'cauliflower', 'zucchini', 'spaghetti squash', 'acorn squash', 'butternut squash', 'cucumber', 'artichoke', 'cardoon', 'mushroom', 'shower curtain', 'jean', 'carton', 'handkerchief', 'sandal', 'ashcan', 'safe', 'plate', 'necklace', 'croquet ball', 'fur coat', 'thimble', 'pajama', 'running shoe', 'cocktail shaker', 'chest', 'manhole cover', 'modem', 'tub', 'tray', 'balance beam', 'bagel', 'prayer rug', 'kimono', 'hot pot', 'whiskey jug', 'knee pad', 'book jacket', 'spindle', 'ski mask', 'beer bottle', 'crash helmet', 'bottlecap', 'tile roof', 'mask', 'maillot', 'Petri dish', 'football helmet', 'bathing cap', 'teddy', 'holster', 'pop bottle', 'photocopier', 'vestment', 'crossword puzzle', 'golf ball', 'trifle', 'suit', 'water tower', 'feather boa', 'cloak', 'red wine', 'drumstick', 'shield', 'Christmas stocking', 'hoopskirt', 'menu', 'stage', 'bonnet', 'meat loaf', 'baseball', 'face powder', 'scabbard', 'sunscreen', 'beer glass', 'hen-of-the-woods', 'guacamole', 'lampshade', 'wool', 'hay', 'bow tie', 'mailbag', 'water jug', 'bucket', 'dishrag', 'soup bowl', 'eggnog', 'mortar', 'trench coat', 'paddle', 'chain', 'swab', 'mixing bowl', 'potpie', 'wine bottle', 'shoji', 'bulletproof vest', 'drilling platform', 'binder', 'cardigan', 'sweatshirt', 'pot', 'birdhouse', 'hamper', 'ping-pong ball', 'pencil box', 'pay-phone', 'consomme', 'apron', 'punching bag', 'backpack', 'groom', 'bearskin', 'pencil sharpener', 'broom', 'mosquito net', 'abaya', 'mortarboard', 'poncho', 'crutch', 'Polaroid camera', 'space bar', 'cup', 'racket', 'traffic light', 'quill', 'radio', 'dough', 'cuirass', 'military uniform', 'lipstick', 'shower cap', 'monitor', 'oscilloscope', 'mitten', 'brassiere', 'French loaf', 'vase', 'milk can', 'rugby ball', 'paper towel', 'earthstar', 'envelope', 'miniskirt', 'cowboy hat', 'trolleybus', 'perfume', 'bathtub', 'hotdog', 'coral fungus', 'bullet train', 'pillow', 'toilet tissue', 'cassette', "carpenter's kit", 'ladle', 'stinkhorn', 'lotion', 'hair spray', 'academic gown', 'dome', 'crate', 'wig', 'burrito', 'pill bottle', 'chain mail', 'theater curtain', 'window shade', 'barrel', 'washbasin', 'ballpoint', 'basketball', 'bath towel', 'cowboy boot', 'gown', 'window screen', 'agaric', 'cellular telephone', 'nipple', 'barbell', 'mailbox', 'lab coat', 'fire screen', 'minibus', 'packet', 'maze', 'pole', 'horizontal bar', 'sombrero', 'pickelhaube', 'rain barrel', 'wallet', 'cassette player', 'comic book', 'piggy bank', 'street sign', 'bell cote', 'fountain pen', 'Windsor tie', 'volleyball', 'overskirt', 'sarong', 'purse', 'bolo tie', 'bib', 'parachute', 'sleeping bag', 'television', 'swimming trunks', 'measuring cup', 'espresso', 'pizza', 'breastplate', 'shopping basket', 'wooden spoon', 'saltshaker', 'chocolate sauce', 'ballplayer', 'goblet', 'gyromitra', 'stretcher', 'water bottle', 'dial telephone', 'soap dispenser', 'jersey', 'school bus', 'jigsaw puzzle', 'plastic bag', 'reflex camera', 'diaper', 'Band Aid', 'ice lolly', 'velvet', 'tennis ball', 'gasmask', 'doormat', 'Loafer', 'ice cream', 'pretzel', 'quilt', 'maillot', 'tape player', 'clog', 'iPod', 'bolete', 'scuba diver', 'pitcher', 'matchstick', 'bikini', 'sock', 'CD player', 'lens cap', 'thatch', 'vault', 'beaker', 'bubble', 'cheeseburger', 'parallel bars', 'flagpole', 'coffee mug', 'rubber eraser', 'stole', 'carbonara', 'dumbbell'] \ No newline at end of file From 1cc384c63067f15a2128ce3320a1c3621c448971 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Sun, 21 Apr 2024 15:45:01 +0000 Subject: [PATCH 45/91] Change label directory --- tools/open_dataset_tool/imagenet1k.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/open_dataset_tool/imagenet1k.py b/tools/open_dataset_tool/imagenet1k.py index 512bb5491..2ffb3d3ca 100644 --- a/tools/open_dataset_tool/imagenet1k.py +++ b/tools/open_dataset_tool/imagenet1k.py @@ -96,7 +96,7 @@ # Build train label csv file print('Building train label csv file ...') - train_label_dir = imagenet_path / 'labels' / 'train' + train_label_dir = imagenet_path / 'labels' os.makedirs(train_label_dir, exist_ok=True) samples = os.listdir(imagenet_path / 'images' / 'train') @@ -110,7 +110,7 @@ # Build valid label csv file print('Building valid label csv file ...') - valid_label_dir = imagenet_path / 'labels' / 'valid' + valid_label_dir = imagenet_path / 'labels' os.makedirs(valid_label_dir, exist_ok=True) with open(devkit_extracted / 'data' / 'ILSVRC2012_validation_ground_truth.txt') as f: From 49b1e15746f6d0013ba3f1d0623293753ddbf1ac Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Sun, 21 Apr 2024 15:48:49 +0000 Subject: [PATCH 46/91] Fix typo --- config/data/cifar100.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/data/cifar100.yaml b/config/data/cifar100.yaml index 77fc10ea9..d90efb951 100644 --- a/config/data/cifar100.yaml +++ b/config/data/cifar100.yaml @@ -6,10 +6,10 @@ data: root: ./data/cifar-100 # dataset root train: image: images/train # directory for training images - label: labels/cifar100_train.csv # label for training labels + label: labels/cifar100_train.csv # directory for training labels or csv file valid: image: images/valid # directory for valid images - label: labels/cifar100_val.csv # durectory for valid labels + label: labels/cifar100_val.csv # directory for valid labels or csv file test: image: ~ label: ~ From ab2c0b9b1b0238eb25022675fef06526dcb0e715 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Sun, 21 Apr 2024 15:49:49 +0000 Subject: [PATCH 47/91] Update voc12.yaml --- config/data/voc12.yaml | 14 +++++++------- config/data/voc12_grayscale_converted.yaml | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/config/data/voc12.yaml b/config/data/voc12.yaml index d331fc485..24952a5db 100644 --- a/config/data/voc12.yaml +++ b/config/data/voc12.yaml @@ -3,16 +3,16 @@ data: task: segmentation format: local path: - root: /DATA/VOC12Dataset + root: ./data/voc2012_seg # dataset root train: - image: image/train - label: mask/train + image: images/train # directory for training images + label: labels/train # directory for training labels valid: - image: image/val - label: mask/val + image: images/valid # directory for valid images + label: labels/valid # directory for valid labels test: - image: ~ # directory for test images - label: ~ # directory for test labels + image: ~ + label: ~ pattern: image: ~ label: ~ diff --git a/config/data/voc12_grayscale_converted.yaml b/config/data/voc12_grayscale_converted.yaml index 159bb5b4c..29be8d0a8 100644 --- a/config/data/voc12_grayscale_converted.yaml +++ b/config/data/voc12_grayscale_converted.yaml @@ -3,16 +3,16 @@ data: task: segmentation format: local path: - root: ../../data/VOC12Dataset + root: ./data/voc2012_seg train: - image: image/train - label: mask/train + image: images/train # directory for training images + label: labels/train # directory for training labels valid: - image: image/val - label: mask/val + image: images/valid # directory for valid images + label: labels/valid # directory for valid labels test: - image: ~ # directory for test images - label: ~ # directory for test labels + image: ~ + label: ~ pattern: image: ~ label: ~ From 72438235eca5af34bcb94b13ff0eb4187ac8cad0 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Sun, 21 Apr 2024 15:50:55 +0000 Subject: [PATCH 48/91] Update coco2017.yaml --- config/data/coco2017.yaml | 20 ++++++++++++++++++++ config/data/coco_yolo.yaml | 27 --------------------------- 2 files changed, 20 insertions(+), 27 deletions(-) create mode 100644 config/data/coco2017.yaml delete mode 100644 config/data/coco_yolo.yaml diff --git a/config/data/coco2017.yaml b/config/data/coco2017.yaml new file mode 100644 index 000000000..fc6d969b0 --- /dev/null +++ b/config/data/coco2017.yaml @@ -0,0 +1,20 @@ +data: + name: coco2017 + task: detection + format: local # local, huggingface + path: + root: ./data/coco2017 # dataset root + train: + image: images/train # directory for training images + label: labels/train # directory for training labels + valid: + image: images/valid # directory for valid images + label: labels/valid # directory for valid labels + test: + image: ~ + label: ~ + pattern: + image: ~ + label: ~ + id_mapping: ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] + pallete: ~ diff --git a/config/data/coco_yolo.yaml b/config/data/coco_yolo.yaml deleted file mode 100644 index 3cdd30d0c..000000000 --- a/config/data/coco_yolo.yaml +++ /dev/null @@ -1,27 +0,0 @@ -data: - name: coco_for_yolo_model - task: detection - format: local # local, huggingface - path: - root: /DATA/coco # dataset root - train: - image: images/train2017 # directory for training images - label: labels/train2017 # directory for training labels - valid: - image: images/val2017 # directory for valid images - label: labels/val2017 # directory for valid labels - test: - image: ~ # directory for test images - label: ~ - pattern: - image: "([0-9]{12})\\.jpg" # regex for filepath whose id is grouped. If None, jointly paired with sorted lists - label: "([0-9]{12})\\.txt" # regex for filepath whose id is grouped. If None, jointly paired with sorted lists - id_mapping: ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', - 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', - 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', - 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', - 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', - 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', - 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', - 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', - 'hair drier', 'toothbrush'] # class names \ No newline at end of file From ae649392d85d140f9cdc015888aecf8fdf067f07 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Sun, 21 Apr 2024 15:52:21 +0000 Subject: [PATCH 49/91] Remove word --- tools/open_dataset_tool/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/open_dataset_tool/README.md b/tools/open_dataset_tool/README.md index f0f59a9ae..cc2135421 100644 --- a/tools/open_dataset_tool/README.md +++ b/tools/open_dataset_tool/README.md @@ -1,6 +1,6 @@ ## Dataset preparation (Local) -If you are interested in utilizing well-known open datasets, you can exploit them by following the instructions. +If you are interested in utilizing open datasets, you can exploit them by following the instructions. ### Image classification From 9427ca09820e781b62151299a956164725cb6939 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Sun, 21 Apr 2024 15:54:36 +0000 Subject: [PATCH 50/91] Sort out data configs --- config/data/{ => huggingface}/beans.yaml | 0 .../{ => huggingface}/chest-xray-classification.yaml | 0 config/data/{ => huggingface}/sidewalk-semantic.yaml | 0 config/data/{ => huggingface}/skin_cancer.yaml | 0 config/data/{ => huggingface}/wikiart-artist.yaml | 0 config/data/{ => local}/chess.yaml | 0 config/data/{ => local}/cifar100.yaml | 0 config/data/{ => local}/coco2017.yaml | 0 config/data/{ => local}/imagenet1k.yaml | 0 config/data/{ => local}/rcv-workshop-iccv2023.yaml | 0 config/data/{ => local}/traffic-sign.yaml | 6 +++--- config/data/{ => local}/voc12.yaml | 0 config/data/{ => local}/voc12_grayscale_converted.yaml | 0 config/data/{ => local}/wflw.yaml | 0 config/data/sample_classification_label.csv | 9 --------- 15 files changed, 3 insertions(+), 12 deletions(-) rename config/data/{ => huggingface}/beans.yaml (100%) rename config/data/{ => huggingface}/chest-xray-classification.yaml (100%) rename config/data/{ => huggingface}/sidewalk-semantic.yaml (100%) rename config/data/{ => huggingface}/skin_cancer.yaml (100%) rename config/data/{ => huggingface}/wikiart-artist.yaml (100%) rename config/data/{ => local}/chess.yaml (100%) rename config/data/{ => local}/cifar100.yaml (100%) rename config/data/{ => local}/coco2017.yaml (100%) rename config/data/{ => local}/imagenet1k.yaml (100%) rename config/data/{ => local}/rcv-workshop-iccv2023.yaml (100%) rename config/data/{ => local}/traffic-sign.yaml (76%) rename config/data/{ => local}/voc12.yaml (100%) rename config/data/{ => local}/voc12_grayscale_converted.yaml (100%) rename config/data/{ => local}/wflw.yaml (100%) delete mode 100644 config/data/sample_classification_label.csv diff --git a/config/data/beans.yaml b/config/data/huggingface/beans.yaml similarity index 100% rename from config/data/beans.yaml rename to config/data/huggingface/beans.yaml diff --git a/config/data/chest-xray-classification.yaml b/config/data/huggingface/chest-xray-classification.yaml similarity index 100% rename from config/data/chest-xray-classification.yaml rename to config/data/huggingface/chest-xray-classification.yaml diff --git a/config/data/sidewalk-semantic.yaml b/config/data/huggingface/sidewalk-semantic.yaml similarity index 100% rename from config/data/sidewalk-semantic.yaml rename to config/data/huggingface/sidewalk-semantic.yaml diff --git a/config/data/skin_cancer.yaml b/config/data/huggingface/skin_cancer.yaml similarity index 100% rename from config/data/skin_cancer.yaml rename to config/data/huggingface/skin_cancer.yaml diff --git a/config/data/wikiart-artist.yaml b/config/data/huggingface/wikiart-artist.yaml similarity index 100% rename from config/data/wikiart-artist.yaml rename to config/data/huggingface/wikiart-artist.yaml diff --git a/config/data/chess.yaml b/config/data/local/chess.yaml similarity index 100% rename from config/data/chess.yaml rename to config/data/local/chess.yaml diff --git a/config/data/cifar100.yaml b/config/data/local/cifar100.yaml similarity index 100% rename from config/data/cifar100.yaml rename to config/data/local/cifar100.yaml diff --git a/config/data/coco2017.yaml b/config/data/local/coco2017.yaml similarity index 100% rename from config/data/coco2017.yaml rename to config/data/local/coco2017.yaml diff --git a/config/data/imagenet1k.yaml b/config/data/local/imagenet1k.yaml similarity index 100% rename from config/data/imagenet1k.yaml rename to config/data/local/imagenet1k.yaml diff --git a/config/data/rcv-workshop-iccv2023.yaml b/config/data/local/rcv-workshop-iccv2023.yaml similarity index 100% rename from config/data/rcv-workshop-iccv2023.yaml rename to config/data/local/rcv-workshop-iccv2023.yaml diff --git a/config/data/traffic-sign.yaml b/config/data/local/traffic-sign.yaml similarity index 76% rename from config/data/traffic-sign.yaml rename to config/data/local/traffic-sign.yaml index c5aadcf62..3a2516931 100644 --- a/config/data/traffic-sign.yaml +++ b/config/data/local/traffic-sign.yaml @@ -3,7 +3,7 @@ data: task: detection format: local # local, huggingface path: - root: ../../data/traffic-sign # dataset root + root: ../data/traffic-sign # dataset root train: image: images/train # directory for training images label: labels/train # directory for training labels @@ -11,8 +11,8 @@ data: image: images/val # directory for valid images label: labels/val # directory for valid labels test: - image: ~ # directory for test images - label: ~ # directory for test labels + image: images/val #images/val + label: labels/val #labels/val # directory for valid labels pattern: image: ~ label: ~ diff --git a/config/data/voc12.yaml b/config/data/local/voc12.yaml similarity index 100% rename from config/data/voc12.yaml rename to config/data/local/voc12.yaml diff --git a/config/data/voc12_grayscale_converted.yaml b/config/data/local/voc12_grayscale_converted.yaml similarity index 100% rename from config/data/voc12_grayscale_converted.yaml rename to config/data/local/voc12_grayscale_converted.yaml diff --git a/config/data/wflw.yaml b/config/data/local/wflw.yaml similarity index 100% rename from config/data/wflw.yaml rename to config/data/local/wflw.yaml diff --git a/config/data/sample_classification_label.csv b/config/data/sample_classification_label.csv deleted file mode 100644 index 0a4f25813..000000000 --- a/config/data/sample_classification_label.csv +++ /dev/null @@ -1,9 +0,0 @@ -image_id,class -dog1.jpg,dog -dog2.jpg,dog -dog3.jpg,dog -cat1.jpg,cat -cat2.jpg,cat -cat3.jpg,cat -magic_photo.jpg,cat -my_pic_from_iphone.png,dog From c0ea3b51bcba7d0a38f2a8310e7f27f268cf9ad9 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Mon, 22 Apr 2024 05:47:15 +0000 Subject: [PATCH 51/91] Fix test directory check line --- src/netspresso_trainer/dataloaders/builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/netspresso_trainer/dataloaders/builder.py b/src/netspresso_trainer/dataloaders/builder.py index e7c98b48f..459ec72db 100644 --- a/src/netspresso_trainer/dataloaders/builder.py +++ b/src/netspresso_trainer/dataloaders/builder.py @@ -27,7 +27,7 @@ def dataset_path_check(conf_data: DictConfig, mode: Literal['train', 'test']): conf_data.path.test.label = None elif mode == 'test': - assert conf_data.path.train.test_dataset is not None, "For test, test split of dataset must be provided." + assert conf_data.path.test.image is not None, "For test, test split of dataset must be provided." if conf_data.path.train.image: logger.warning('For test (evaluation or inference), train split of dataset is not needed. This field will be ignored.') From 70dbe9bb2291a5715ba75eb85dc908443d2356c8 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Mon, 22 Apr 2024 05:54:19 +0000 Subject: [PATCH 52/91] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85d60d11b..0d60f8a8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ ## Bug Fixes: -No changes to highlight. +- Fix test directory check line by `@illian01` in [PR 428](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/428) ## Breaking Changes: From 6dd90df11ef692097cad52fa89ad56f8e6880ddc Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Mon, 22 Apr 2024 06:28:27 +0000 Subject: [PATCH 53/91] Move tools readme to docs --- .../dataset_preparation/local.md | 32 +++++++------------ 1 file changed, 12 insertions(+), 20 deletions(-) rename tools/open_dataset_tool/README.md => docs/getting_started/dataset_preparation/local.md (76%) diff --git a/tools/open_dataset_tool/README.md b/docs/getting_started/dataset_preparation/local.md similarity index 76% rename from tools/open_dataset_tool/README.md rename to docs/getting_started/dataset_preparation/local.md index cc2135421..4bc102ba9 100644 --- a/tools/open_dataset_tool/README.md +++ b/docs/getting_started/dataset_preparation/local.md @@ -1,23 +1,20 @@ -## Dataset preparation (Local) +# Data preparation (Local) If you are interested in utilizing open datasets, you can exploit them by following the instructions. -### Image classification +## Image classification -
-CIFAR100 - -Simply run `cifar100.py` python file with your dataset directory as an argument. +### CIFAR100 + +Run `cifar100.py` python file with your dataset directory as an argument. CIFAR100 dataset will be automatically downloaded to `./data/download`. After executing scripts, you can use [pre-defined configuration](https://github.com/Nota-NetsPresso/netspresso-trainer/blob/dev/config/data/cifar100.yaml). ```bash python ./tools/open_dataset_tool/cifar100.py --dir ./data ``` -
-
-ImageNet1K +### ImageNet1K ImageNet1K dataset cannot be automatically downloaded. You should download dataset from [ImageNet](https://www.image-net.org/) website, and place downloaded files into `./data/download`. @@ -28,32 +25,27 @@ And, run `imagenet1k.py` python file with your dataset directorty and downloaded ```bash python ./tools/open_dataset_tool/imagenet1k.py --dir ./data --train-images ./data/download/ILSVRC2012_img_train.tar --valid-images ./data/download/ILSVRC2012_img_val.tar --devkit ./data/download/ILSVRC2012_devkit_t12.tar.gz ``` -
-### Semantic segmentation +## Semantic segmentation -
-PascalVOC 2012 +### PascalVOC 2012 -Simply run `voc2012_seg.py` python file with your dataset directory as an argument. +Run `voc2012_seg.py` python file with your dataset directory as an argument. PascalVOC 2012 dataset will be automatically downloaded to `./data/download`. After executing scripts, you can use [pre-defined configuration](https://github.com/Nota-NetsPresso/netspresso-trainer/blob/dev/config/data/voc12.yaml). ```bash python ./tools/open_dataset_tool/voc2012_seg.py --dir ./data ``` -
-### Object detection +## Object detection -
-COCO 2017 +### COCO 2017 -Simply run `coco2017.py` python file with your dataset directory as an argument. +Run `coco2017.py` python file with your dataset directory as an argument. COCO 2017 dataset will be automatically downloaded to `./data/download`. After executing scripts, you can use [pre-defined configuration](https://github.com/Nota-NetsPresso/netspresso-trainer/blob/dev/config/data/coco2017.yaml). ```bash python ./tools/open_dataset_tool/coco2017.py --dir ./data ``` -
From 726e8dd02717fba1e042ed1c4d2ecd0afe940f6a Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Mon, 22 Apr 2024 13:10:54 +0000 Subject: [PATCH 54/91] Update docs --- docs/components/data.md | 534 ++++++++++-------- docs/components/overview.md | 2 +- .../dataset_preparation/huggingface.md | 91 +++ .../dataset_preparation/local.md | 126 ++++- mkdocs.yml | 3 + 5 files changed, 492 insertions(+), 264 deletions(-) create mode 100644 docs/getting_started/dataset_preparation/huggingface.md diff --git a/docs/components/data.md b/docs/components/data.md index f7e9c4a0f..aca4b2a68 100644 --- a/docs/components/data.md +++ b/docs/components/data.md @@ -5,12 +5,36 @@ In addition to data stored in a local repository, it also supports learning with Currently, the dataset formats supported by NetsPresso Trainer are fixed in a specific form, but we plan to expand to more dataset formats such as COCO format in the future. On this page, we will guide you on the data format you need to learn with your custom data and how to learn using Hugging Face datasets. -## Supporting format + +## Local custom datasets + +### Supporting image formats For image data, various extension images are supported, but we recommend one of `.jpg`, `.jpeg`, `.png`, and `.bmp`. In this case, label data used in semantic segmentation must be saved as `.png` to prevent data loss and utilize image header information. The following sections introduce how to organize data for each task. -## Training with your custom datasets +### Common configuration + +Regardless of the task, dataset directory should be organized as follows: + +- **Train**: This directory should contain all the training images and corresponding label files. +- **Validation**: This directory should house validation images and their corresponding labels, used to tune the hyperparameters. +- **Test**: This directory should include test images and labels for final model evaluation. + +This structure should be reflected in your configuration file under the respective paths. + +| Field | Description | +|---|---| +| `data.name` | (str) The name of dataset. | +| `data.task` | (str) `classification` for image classification, `segmentation` for semantic segmentation, and `detection` for object detection. | +| `data.format` | **`local`** as an identifier of dataset format. | +| `data.path.root` | (str) Root directory of dataset. | +| `data.path.train.image` | (str) The directory for training images. Should be **relative** path to root directory. | +| `data.path.train.label` | (str) The directory for training labels or label file (depends on the task). This should be **relative** path to root directory. | +| `data.path.valid.image` | (str) The directory for validation images. Should be **relative** path to root directory. | +| `data.path.valid.label` | (str) The directory for validation labels or label file (depends on the task). This should be **relative** path to root directory. | +| `data.path.test.image` | (str) The directory for test images. Should be **relative** path to root directory. | +| `data.path.test.label` | (str) The directory for test labels or label file (depends on the task). This should be **relative** path to root directory. | ### Image classification @@ -20,57 +44,69 @@ To train an image classification model using NetsPresso Trainer, **users must or - validation images must be in same directory. - labels for images are given by csv file. The csv file contains image file name and correspoinding class label. -The example data directory structure for this is as follows. The following examples use the [ImageNet1K](https://image-net.org/) dataset.: - -``` -IMAGENET1K -├── images -│ ├── train -│ │ ├── n01440764_10026.JPEG -│ │ ├── n01440764_10027.JPEG -│ │ ├── n01440764_10029.JPEG -│ │ └── ... -│ └── valid -│ ├── ILSVRC2012_val_00000001.JPEG -│ ├── ILSVRC2012_val_00000002.JPEG -│ ├── ILSVRC2012_val_00000003.JPEG -│ └── ... -└── labels - ├── imagenet_train.csv - └── imagenet_valid.csv -``` - -An example yaml configuration for this is as follows: - -```yaml -data: - name: imagenet1k - task: classification - format: local # local, huggingface - path: - root: path_to/IMAGENET1K # dataset root - train: - image: train # directory for training images - label: imagenet_train.csv # label for training images - valid: - image: val # directory for valid images - label: imagenet_valid.csv # label for valid images - test: - image: ~ # directory for test images - label: ~ # label for test images - id_mapping: ["kit fox", "English setter", "Siberian husky", "Australian terrier", ...] -``` - -An example csv label for this is as follows: - -| image_id | class | -|----------------------|----------| -| n03792972_3671.JPEG | 728 | -| n04357314_4256.JPEG | 810 | -| n02965783_127.JPEG | 576 | -| n04465501_16825.JPEG | 289 | -| n09246464_5059.JPEG | 359 | -| ... | ... | +| Field | Description | +|---|---| +| `data.id_mapping` | (list) Class list for each class index. | +| `data.path.train.label` | (str) For classificaiton, label field must be path of .csv file. This should be **relative** path to root directory. | +| `data.path.valid.label` | (str) For classificaiton, label field must be path of .csv file. This should be **relative** path to root directory. | +| `data.path.test.label` | (str) For classificaiton, label field must be path of .csv file. This should be **relative** path to root directory. | + +
+ Data hierarchy example - ImageNet1K + ```text + data/imagenet1k + ├── images + │ ├── train + │ │ ├── n01440764_10026.JPEG + │ │ ├── n01440764_10027.JPEG + │ │ ├── n01440764_10029.JPEG + │ │ └── ... + │ └── valid + │ ├── ILSVRC2012_val_00000001.JPEG + │ ├── ILSVRC2012_val_00000002.JPEG + │ ├── ILSVRC2012_val_00000003.JPEG + │ └── ... + └── labels + ├── imagenet_train.csv + └── imagenet_valid.csv + ``` +
+ +
+ Label csv example - ImageNet1K + ```text + | image_id | class | + |----------------------|----------| + | n03792972_3671.JPEG | 728 | + | n04357314_4256.JPEG | 810 | + | n02965783_127.JPEG | 576 | + | n04465501_16825.JPEG | 289 | + | n09246464_5059.JPEG | 359 | + | ... | ... | + ``` +
+ +
+ Data configuration example - ImageNet1K + ```yaml + data: + name: imagenet1k + task: classification + format: local # local, huggingface + path: + root: path_to/IMAGENET1K # dataset root + train: + image: images/train # directory for training images + label: labels/imagenet_train.csv # label for training images + valid: + image: images/valid # directory for valid images + label: labels/imagenet_valid.csv # label for valid images + test: + image: ~ # directory for test images + label: ~ # label for test images + id_mapping: ["kit fox", "English setter", "Siberian husky", "Australian terrier", ...] + ``` +
### Semantic segmentation @@ -81,218 +117,197 @@ To train a semantic segmentation model using NetsPresso Trainer, **the data must - In this case, training data and validation data can be distinguished in different directories. For example, training data can be placed in train/image, train/label directories, and validation data can be placed in valid/image, valid/label directories. - Users must know the class name corresponding to each pixel value (RGB or L (grayscale) format) in the label file. -The example data directory structure for this is as follows: - -``` -VOC12Dataset -├── image -│ ├── train -│ │ ├── 2007_000032.jpg -│ │ ├── 2007_000039.jpg -│ │ ├── 2007_000063.jpg -│ │ └── ... -│ └── val -│ ├── 2007_000033.jpg -│ ├── 2007_000042.jpg -│ ├── 2007_000061.jpg -│ └── ... -└── mask - ├── train - │ ├── 2007_000032.png - │ ├── 2007_000039.png - │ ├── 2007_000063.png - │ └── ... - └── val - ├── 2007_000033.png - ├── 2007_000042.png - ├── 2007_000061.png - └── ... -``` - -An example yaml configuration for this is as follows: - -```yaml -data: - name: voc2012 - task: segmentation - format: local - path: - root: path_to/VOC12Dataset - train: - image: image/train - label: mask/train - valid: - image: image/val - label: mask/val - test: - image: ~ # directory for test images - label: ~ # directory for test labels - pattern: - image: ~ - label: ~ - label_image_mode: RGB - id_mapping: - (0, 0, 0): background - (128, 0, 0): aeroplane - (0, 128, 0): bicycle - (128, 128, 0): bird - (0, 0, 128): boat - (128, 0, 128): bottle - (0, 128, 128): bus - (128, 128, 128): car - (64, 0, 0): cat - (192, 0, 0): chair - (64, 128, 0): cow - (192, 128, 0): diningtable - (64, 0, 128): dog - (192, 0, 128): horse - (64, 128, 128): motorbike - (192, 128, 128): person - (0, 64, 0): pottedplant - (128, 64, 0): sheep - (0, 192, 0): sofa - (128, 192, 0): train - (0, 64, 128): tvmonitor - (128, 64, 128): void - pallete: ~ -``` +| Field | Description | +|---|---| +| `data.label_image_mode` | (str) Image mode to convert the label. Should be one of `RGB`, `L`, and `P`. This field is not case-sensitive. | +| `data.path.train.label` | (str) For segmentation, label field must be path of label directory. This should be **relative** path to root directory. | +| `data.path.valid.label` | (str) For segmentation, label field must be path of label directory. This should be **relative** path to root directory. | +| `data.path.test.label` | (str) For segmentation, label field must be path of label directory. This should be **relative** path to root directory. | +| `data.id_mapping` | (dict, list) Key-value pair between label value (`RGB`, `L`, or `P`) and class name. Should be a dict of {**label_value: classname**} or a list of class names whose indices are same with the label value (image_mode: `L` or `P`). | +| `data.palette` | (dict) Color mapping for visualization. If `none`, automatically select the color for each class. | + + +
+ Data hierarchy example - PascalVOC 2012 + ```text + data/voc2012_seg + ├── images + │ ├── train + │ │ ├── 2007_000032.jpg + │ │ ├── 2007_000039.jpg + │ │ ├── 2007_000063.jpg + │ │ └── ... + │ └── valid + │ ├── 2007_000033.jpg + │ ├── 2007_000042.jpg + │ ├── 2007_000061.jpg + │ └── ... + └── labels + ├── train + │ ├── 2007_000032.png + │ ├── 2007_000039.png + │ ├── 2007_000063.png + │ └── ... + └── valid + ├── 2007_000033.png + ├── 2007_000042.png + ├── 2007_000061.png + └── ... + ``` +
+ +
+ Data configuration example - PascalVOC 2012 + ```yaml + data: + name: voc2012 + task: segmentation + format: local + path: + root: path_to/VOC12Dataset + train: + image: image/train + label: mask/train + valid: + image: image/valid + label: mask/valid + test: + image: ~ # directory for test images + label: ~ # directory for test labels + pattern: + image: ~ + label: ~ + label_image_mode: RGB + id_mapping: + (0, 0, 0): background + (128, 0, 0): aeroplane + (0, 128, 0): bicycle + (128, 128, 0): bird + (0, 0, 128): boat + (128, 0, 128): bottle + (0, 128, 128): bus + (128, 128, 128): car + (64, 0, 0): cat + (192, 0, 0): chair + (64, 128, 0): cow + (192, 128, 0): diningtable + (64, 0, 128): dog + (192, 0, 128): horse + (64, 128, 128): motorbike + (192, 128, 128): person + (0, 64, 0): pottedplant + (128, 64, 0): sheep + (0, 192, 0): sofa + (128, 192, 0): train + (0, 64, 128): tvmonitor + (128, 64, 128): void + pallete: ~ + ``` +
### Object detection To train an object detection model using NetsPresso Trainer, **the data must be in the following formats**: - For object detection model training, each training image must have a corresponding `.txt` file indicating the original image and the bounding box and class index corresponding to each bounding box of the image. -- The format of the bounding box follows the YOLO dataset format ([x_center, y_center, width, height], normalized). +- The format of the bounding box follows the YOLO dataset format `[x_center, y_center, width, height]` (normalized). - Each `.txt` file must contain one line for each bounding box. - In this case, training data and validation data can be distinguished in different directories. For example, training data can be placed in train/image, train/label directories, and validation data can be placed in valid/image, valid/label directories. - Users must know the class name corresponding to each class index in the label file. -The example data directory structure for this is as follows: - -``` -traffic-sign -├── images -│ ├── train -│ │ ├── 00000.jpg -│ │ ├── 00001.jpg -│ │ ├── 00003.jpg -│ │ └── ... -│ └── val -│ ├── 00002.jpg -│ ├── 00004.jpg -│ ├── 00015.jpg -│ └── ... -└── labels - ├── train - │ ├── 00000.txt - │ ├── 00001.txt - │ ├── 00003.txt - │ └── ... - └── val - ├── 00002.txt - ├── 00004.txt - ├── 00015.txt - └── ... -``` - -An example yaml configuration for this is as follows: - -```yaml -# This example dataset is downloaded from -data: - name: traffic_sign_yolo - task: detection - format: local # local, huggingface - path: - root: path_to/traffic-sign # dataset root - train: - image: images/train # directory for training images - label: labels/train # directory for training labels - valid: - image: images/val # directory for valid images - label: labels/val # directory for valid labels - test: - image: ~ # directory for test images - label: ~ # directory for test labels - pattern: - image: ~ - label: ~ - id_mapping: ['prohibitory', 'danger', 'mandatory', 'other'] # class names - pallete: ~ -``` - -An example txt label for this is as follows: - -``` -2 0.7378676470588236 0.5125 0.030147058823529412 0.055 -2 0.3044117647058823 0.65375 0.041176470588235294 0.0725 -3 0.736764705882353 0.453125 0.04264705882352941 0.06875 -``` - -## Training with Hugging Face datasets - -NetsPresso Trainer is striving to support various dataset hubs and platforms. -As part of that effort and first step, NetsPresso Trainer can be used with data in [Hugging Face datasets](https://huggingface.co/datasets). - -An example configuration for Hugging Face datasets is as follows: - -```yaml -data: - name: beans - task: classification - format: huggingface - metadata: - custom_cache_dir: ./data/huggingface - repo: beans - subset: ~ - features: - image: image - label: labels - -``` - -## Field list - -### Local dataset - -#### Common - -| Field | Description | -|---|---| -| `data.name` | (str) The name of dataset. | -| `data.task` | (str) `classification` for image classification, `segmentation` for semantic segmentation, and `detection` for object detection. | -| `data.format` | **`local`** as an identifier of dataset format. | -| `data.path.root` | (str) Root directory of dataset. | -| `data.path.train.image` | (str) The directory for training images. Should be **relative** path to root directory. | -| `data.path.train.label` | (str) The directory for training labels. Should be **relative** path to root directory. | -| `data.path.valid.image` | (str) The directory for validation images. Should be **relative** path to root directory. | -| `data.path.valid.label` | (str) The directory for validation labels. Should be **relative** path to root directory. | -| `data.path.test.image` | (str) The directory for test images. Should be **relative** path to root directory. | -| `data.path.test.label` | (str) The directory for test labels. Should be **relative** path to root directory. | - -#### Classification - -| Field | Description | -|---|---| -| `data.id_mapping` | (dict) Key-value pair between directory name and class name. Should be a dict of {**dirname: classname**}. | - -#### Segmentation - -| Field | Description | -|---|---| -| `data.label_image_mode` | (str) Image mode to convert the label. Should be one of `RGB`, `L`, and `P`. This field is not case-sensitive. -| `data.id_mapping` | (dict, list) Key-value pair between label value (`RGB`, `L`, or `P`) and class name. Should be a dict of {**label_value: classname**} or a list of class names whose indices are same with the label value (image_mode: `L` or `P`). | -| `data.palette` | (dict) Color mapping for visualization. If `none`, automatically select the color for each class. | - -#### Detection - | Field | Description | |---|---| +| `data.path.train.label` | (str) For detection, label field must be path of label directory. This should be **relative** path to root directory. | +| `data.path.valid.label` | (str) For detection, label field must be path of label directory. This should be **relative** path to root directory. | +| `data.path.test.label` | (str) For detection, label field must be path of label directory. This should be **relative** path to root directory. | | `data.id_mapping` | (list) Class list for each class index. | -| `data.palette` | (dict) Color mapping for visualization. If `none`, automatically select the color for each class. | - +| `data.palette` | (dict) Color mapping for visualization. If `none`, automatically select the color for each class. | + +
+ Data hierarchy example - COCO 2017 + ```text + data/coco2017 + ├── images + │ ├── train + │ │ ├── 000000000009.jpg + │ │ ├── 000000000025.jpg + │ │ ├── 000000000030.jpg + │ │ └── ... + │ └── valid + │ ├── 000000000139.jpg + │ ├── 000000000285.jpg + │ ├── 000000000632.jpg + │ └── ... + └── labels + ├── train + │ ├── 000000000009.txt + │ ├── 000000000025.txt + │ ├── 000000000030.txt + │ └── ... + └── valid + ├── 000000000139.txt + ├── 000000000285.txt + ├── 000000000632.txt + └── ... + ``` +
+ +
+ Label txt example - COCO 2017 + ```text + 58 249.32999999999998 177.26 24.7 69.5 + 62 81.69 215.195 149.32 94.87 + 62 597.885 248.555 81.35 78.73 + 56 386.98 269.46500000000003 56.0 102.83 + 56 321.605 267.24 61.83 98.48 + 56 428.28499999999997 263.69 30.17 81.36 + 56 328.19 225.035 21.58 11.59 + 0 439.325 226.615 53.05 138.01 + 0 391.99 190.08 15.12 35.74 + 68 519.59 213.735 14.74 15.97 + 72 503.245 228.495 20.29 108.31 + 73 611.9399999999999 328.745 14.34 45.71 + 73 619.6800000000001 331.46000000000004 12.88 46.44 + 74 454.755 132.06 13.97 21.88 + 75 567.4 354.265 36.68 89.67 + 75 356.445 220.115 11.37 22.55 + 56 417.065 225.28 9.63 12.52 + 75 248.35000000000002 203.805 14.22 17.63 + 75 341.65500000000003 207.865 9.73 16.73 + 60 383.99 275.685 125.56 88.93 + ``` +
+ +
+ Custom object detection dataset example - COCO 2017 + ```yaml + data: + name: coco2017 + task: detection + format: local # local, huggingface + path: + root: ./data/coco2017 # dataset root + train: + image: images/train # directory for training images + label: labels/train # directory for training labels + valid: + image: images/valid # directory for valid images + label: labels/valid # directory for valid labels + test: + image: ~ + label: ~ + pattern: + image: ~ + label: ~ + id_mapping: ['person', 'bicycle', 'car', ...] + pallete: ~ + ``` +
+ +## Hugging Face datasets -### Hugging Face datasets +NetsPresso Trainer is striving to support various dataset hubs and platforms. +As part of that effort and first step, NetsPresso Trainer can be used with data in [Hugging Face datasets](https://huggingface.co/datasets). | Field | Description | |---|---| @@ -304,3 +319,20 @@ data: | `data.metadata.subset` | (str, optional) Subset name if the dataset contains multiple versions. | | `data.metadata.features.image` | (str) The key representing the image at the dataset header. | | `data.metadata.features.label` | (str) The key representing the label at the dataset header. | + +
+ Huggingface dataset example - beans + ```yaml + data: + name: beans + task: classification + format: huggingface + metadata: + custom_cache_dir: ./data/huggingface + repo: beans + subset: ~ + features: + image: image + label: labels + ``` +
\ No newline at end of file diff --git a/docs/components/overview.md b/docs/components/overview.md index 9e27f25da..ccf07ae07 100644 --- a/docs/components/overview.md +++ b/docs/components/overview.md @@ -17,7 +17,7 @@ This component section describes in detail the six configuration modules which a ### Use SOTA models fully compatible with NetsPresso -NetsPresso Trainer provides reimplemented SOTA models that ensure compatibility with NetsPresso. This allows users to avoid expending resources on changing model formats for model compression and device deployment. Therefore, the users can easily exploit SOTA models to their applications. +NetsPresso Trainer provides reimplemented SOTA models that ensure compatibility with NetsPresso. This allows users to avoid expending resources on changing model formats for model compression and device deployment. Therefore, the users can easily utilize SOTA models to their applications. ### Easily trainable with yaml configuration diff --git a/docs/getting_started/dataset_preparation/huggingface.md b/docs/getting_started/dataset_preparation/huggingface.md new file mode 100644 index 000000000..821188fdb --- /dev/null +++ b/docs/getting_started/dataset_preparation/huggingface.md @@ -0,0 +1,91 @@ +# Data preparation (Hugging Face) + +The Hugging Face datasets offers a vast array of datasets to support various tasks, making them readily accessible through a user-friendly API. Provided datasets in Hugging Face datasets are typically structured into `training`, `validation`, and `testing` sets. This structure allows NetsPresso Trainer to utilize various datasets with yaml configuration. + +To explore official Hugging Face datasets catalogue, please refer to the [hugging Face datasets page](https://huggingface.co/datasets). + +## Hugging Face datasets install + +First, you must install the hugging Face datasets library. + +```bash +pip install -r requirements-optional.txt + +or + +pip install datasets +``` + +## Find dataset repository + +We use [CIFAR100](https://huggingface.co/datasets/cifar100) dataset as an example. Thus, `format` field in data configuration is filled as huggingface, and `metadata.repo` is filled as `cifar100`. + +```yaml +data: + name: cifar100 + task: classification + format: huggingface + metadata: + custom_cache_dir: ./data/huggingface + repo: cifar100 + subset: ~ + features: + image: ~ + label: ~ +``` + +## Agreement the conditions to access the datasets + +Some datasets are publicly available, but require a agreement to use. For example, if you want to use [ImageNet1K](https://huggingface.co/datasets/imagenet-1k) in Hugging Face datasets, you have to log in to Hugging Face homepage and agree on the conditions. + +Make sure to agree the conditions at Hugging Face website, and log in to huggingface-cli before you start. + +```bash +huggingface-cli login +``` + +## Set subset + +Some datasets have multiple subsets in their dataset hierarchy. They have to be specified in `subset` field. + +If there is no subset in the dataset, you can leave `subset` field as null. + +```yaml +data: + name: cifar100 + task: classification + format: huggingface + metadata: + custom_cache_dir: ./data/huggingface + repo: cifar100 + subset: ~ # You have to fill this field if there is subset in the dataset you trying to use + features: + image: ~ + label: ~ +``` + +## Set features + +You can check features of dataset in Hugging Face homepage. If you see [CIFAR100](https://huggingface.co/datasets/cifar100), there are three features in the dataset which are `img`, `fine_label`, `coarse_label`. Since image data is named as `img` and 100-class label is named as `fine_label`, we fill out data configuration as below. + +```yaml +data: + name: cifar100 + task: classification + format: huggingface + metadata: + custom_cache_dir: ./data/huggingface + repo: cifar100 + subset: ~ # You should fill this field if there is subset in the dataset you trying to use + features: + image: img + label: fine_label +``` + +## Run NetsPresso Trainer + +Now you can run NetsPresso Trainer with Hugging Face dataset! + +```bash +python train.py --data your_huggingface_dataset_yaml_path.yaml ... +``` diff --git a/docs/getting_started/dataset_preparation/local.md b/docs/getting_started/dataset_preparation/local.md index 4bc102ba9..835dfc705 100644 --- a/docs/getting_started/dataset_preparation/local.md +++ b/docs/getting_started/dataset_preparation/local.md @@ -1,24 +1,118 @@ # Data preparation (Local) -If you are interested in utilizing open datasets, you can exploit them by following the instructions. +## Local custom datasets -## Image classification +If your dataset is ready in local storage, you can use them by following the instructions. -### CIFAR100 +### Organize dataset + +Create separate directories for images/labels and train/valid/test. + +```text +/my_dataset +├── images +│ ├── train +│ ├── valid +│ └── test +└── labels +``` + +Place your images on proper path. + +```text +/my_dataset +├── images +│ ├── train +│ │ ├── img1.jpg +│ │ ├── img2.jpg +│ │ └── ... +│ ├── valid +│ │ ├── img1.jpg +│ │ ├── img2.jpg +│ │ └── ... +│ └── test +│ ├── img1.jpg +│ ├── img2.jpg +│ └── ... +└── labels +``` + +Set labels on proper path. + +- For image classification, you may need image files and a corresponding label file (usually in csv format). +- For semantic segmentation and object detection, organize your images and label files (could be masks or box annotations) in corresponding folders. + +```text +/my_dataset +├── images +│ ├── train +│ │ ├── img1.jpg +│ │ ├── img2.jpg +│ │ └── ... +│ ├── valid +│ │ ├── img1.jpg +│ │ ├── img2.jpg +│ │ └── ... +│ └── test +│ ├── img1.jpg +│ ├── img2.jpg +│ └── ... +└── labels + └── train directory or file ... + ├── valid directory or file ... + └── test directory or file ... +``` + +*If you just run training, test split may not needed.* + +*If you just run evaluation or inference, train and valid split may not needed.* + +### Set configuration file + +Define the paths to your datasets in the configuration file to tell NetsPresso Trainer where to find the data. Here is example for classification: + +```yaml +data: + name: my_custom_dataset + task: classification # This could be other task + format: local + path: + root: ./my_dataset + train: + image: train/images + label: train/labels.csv + valid: + image: valid/images + label: valid/labels.csv + test: + image: test/images + label: test/labels.csv + id_mapping: [cat, dog, elephant] +``` + +For detailed definition of data configuration, please refer to [components/data](../../components/data.md) + +## Open datasets + +If you are interested in utilizing open datasets, you can use them by following the instructions. These instructions automatically set dataset as local custom datasets format. + +### Image classification + +#### CIFAR100 Run `cifar100.py` python file with your dataset directory as an argument. -CIFAR100 dataset will be automatically downloaded to `./data/download`. After executing scripts, you can use [pre-defined configuration](https://github.com/Nota-NetsPresso/netspresso-trainer/blob/dev/config/data/cifar100.yaml). +CIFAR100 dataset will be automatically downloaded to `./data/download`. After executing scripts, you can use [pre-defined configuration](https://github.com/Nota-NetsPresso/netspresso-trainer/blob/dev/config/data/local/cifar100.yaml). ```bash python ./tools/open_dataset_tool/cifar100.py --dir ./data ``` -### ImageNet1K +#### ImageNet1K ImageNet1K dataset cannot be automatically downloaded. You should download dataset from [ImageNet](https://www.image-net.org/) website, and place downloaded files into `./data/download`. -And, run `imagenet1k.py` python file with your dataset directorty and downloaded files path as arguments. After executing scripts, you can use [pre-defined configuration](). +And, run `imagenet1k.py` python file with your dataset directorty and downloaded files path as arguments. After executing scripts, you can use [pre-defined configuration](https://github.com/Nota-NetsPresso/netspresso-trainer/blob/dev/config/data/local/imagenet1k.yaml). *(`imagenet1k.py` needs scipy library which is in [requirements-optional.txt](https://github.com/Nota-NetsPresso/netspresso-trainer/blob/dev/requirements-optional.txt))* @@ -26,26 +120,34 @@ And, run `imagenet1k.py` python file with your dataset directorty and downloaded python ./tools/open_dataset_tool/imagenet1k.py --dir ./data --train-images ./data/download/ILSVRC2012_img_train.tar --valid-images ./data/download/ILSVRC2012_img_val.tar --devkit ./data/download/ILSVRC2012_devkit_t12.tar.gz ``` -## Semantic segmentation +### Semantic segmentation -### PascalVOC 2012 +#### PascalVOC 2012 Run `voc2012_seg.py` python file with your dataset directory as an argument. -PascalVOC 2012 dataset will be automatically downloaded to `./data/download`. After executing scripts, you can use [pre-defined configuration](https://github.com/Nota-NetsPresso/netspresso-trainer/blob/dev/config/data/voc12.yaml). +PascalVOC 2012 dataset will be automatically downloaded to `./data/download`. After executing scripts, you can use [pre-defined configuration](https://github.com/Nota-NetsPresso/netspresso-trainer/blob/dev/config/data/local/voc12.yaml). ```bash python ./tools/open_dataset_tool/voc2012_seg.py --dir ./data ``` -## Object detection +### Object detection -### COCO 2017 +#### COCO 2017 Run `coco2017.py` python file with your dataset directory as an argument. -COCO 2017 dataset will be automatically downloaded to `./data/download`. After executing scripts, you can use [pre-defined configuration](https://github.com/Nota-NetsPresso/netspresso-trainer/blob/dev/config/data/coco2017.yaml). +COCO 2017 dataset will be automatically downloaded to `./data/download`. After executing scripts, you can use [pre-defined configuration](https://github.com/Nota-NetsPresso/netspresso-trainer/blob/dev/config/data/local/coco2017.yaml). ```bash python ./tools/open_dataset_tool/coco2017.py --dir ./data ``` + +## Run NetsPresso Trainer + +Now you can run NetsPresso Trainer with your local dataset! + +```bash +python train.py --data your_huggingface_dataset_yaml_path.yaml ... +``` \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 2451debe5..aa7eb8d7d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -160,6 +160,9 @@ nav: - Installation (Stable): getting_started/installation/installation.md - Setup with Docker: getting_started/installation/docker_installation.md - Simple use: getting_started/simple_use.md + - Dataset preparation: + - Local dataset: getting_started/dataset_preparation/local.md + - Hugging Face dataset: getting_started/dataset_preparation/huggingface.md - Asking a question: https://github.com/Nota-NetsPresso/netspresso-trainer/issues - Components: - Overview: components/overview.md From 88a3a14dc103ee7f248478823967d89cc2336fd7 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Mon, 22 Apr 2024 13:14:21 +0000 Subject: [PATCH 55/91] Update README.md --- README.md | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index dd8841198..0c29fb431 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,33 @@ Please refer to [`scripts/example_train.sh`](./scripts/example_train.sh). NetsPresso Trainer is compatible with [NetsPresso](https://netspresso.ai/) service. We provide NetsPresso Trainer tutorial that contains whole procedure from model train to model compression and benchmark. Please refer to our [colab tutorial](https://colab.research.google.com/drive/1RBKMCPEa4x-4X31zqzTS8WgQI9TQt3e-?usp=sharing). +## Dataset preparation (Local) + +NetsPresso Trainer is designed to accommodate a variety of tasks, each requiring different dataset formats. You can find the specific dataset formats for each task in our [documentation](https://nota-netspresso.github.io/netspresso-trainer/components/data/). + +If you are interested in utilizing open datasets, you can use them by following the [instructions](https://nota-netspresso.github.io/netspresso-trainer/getting_started/dataset_preparation/local/#open-datasets). + +### Image classification + +- [CIFAR100](https://github.com/Nota-NetsPresso/netspresso-trainer/blob/dev/tools/open_dataset_tool/cifar100.py) +- [ImageNet1K](https://github.com/Nota-NetsPresso/netspresso-trainer/blob/dev/tools/open_dataset_tool/imagenet1k.py) + +### Semantic segmentation + +- [PascalVOC 2012](https://github.com/Nota-NetsPresso/netspresso-trainer/blob/dev/tools/open_dataset_tool/voc2012_seg.py) + +### Object detection + +- [COCO 2017](https://github.com/Nota-NetsPresso/netspresso-trainer/blob/dev/tools/open_dataset_tool/coco2017.py) + +## Dataset preparation (Huggingface) + +NetsPresso Trainer is also compatible with huggingface dataset. To use datasets of huggingface, please check [instructions in our documentations](https://nota-netspresso.github.io/netspresso-trainer/getting_started/dataset_preparation/huggingface/). This enables to utilize a wide range of pre-built datasets which are beneficial for various training scenarios. + +## Pretrained weights + +Please refer to our [official documentation](https://nota-netspresso.github.io/netspresso-trainer/) for pretrained weights supported by NetsPresso Trainer. + ## Tensorboard We provide basic tensorboard to track your training status. Run the tensorboard with the following command: @@ -109,9 +136,4 @@ tensorboard --logdir ./outputs --port 50001 --bind_all ``` where `PORT` for tensorboard is 50001. -Note that the default directory of saving result will be `./outputs` directory. - - -## Pretrained weights - -Please refer to our [official documentation](https://nota-netspresso.github.io/netspresso-trainer/) for pretrained weights supported by NetsPresso Trainer. +Note that the default directory of saving result will be `./outputs` directory. \ No newline at end of file From d15e30854499abe20d103314580b110094cb49c7 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Mon, 22 Apr 2024 13:39:00 +0000 Subject: [PATCH 56/91] Normalize box --- docs/components/data.md | 41 +++++++++++++++-------------- tools/open_dataset_tool/coco2017.py | 31 +++++++++++++++++----- 2 files changed, 46 insertions(+), 26 deletions(-) diff --git a/docs/components/data.md b/docs/components/data.md index aca4b2a68..7899af582 100644 --- a/docs/components/data.md +++ b/docs/components/data.md @@ -255,26 +255,27 @@ To train an object detection model using NetsPresso Trainer, **the data must be
Label txt example - COCO 2017 ```text - 58 249.32999999999998 177.26 24.7 69.5 - 62 81.69 215.195 149.32 94.87 - 62 597.885 248.555 81.35 78.73 - 56 386.98 269.46500000000003 56.0 102.83 - 56 321.605 267.24 61.83 98.48 - 56 428.28499999999997 263.69 30.17 81.36 - 56 328.19 225.035 21.58 11.59 - 0 439.325 226.615 53.05 138.01 - 0 391.99 190.08 15.12 35.74 - 68 519.59 213.735 14.74 15.97 - 72 503.245 228.495 20.29 108.31 - 73 611.9399999999999 328.745 14.34 45.71 - 73 619.6800000000001 331.46000000000004 12.88 46.44 - 74 454.755 132.06 13.97 21.88 - 75 567.4 354.265 36.68 89.67 - 75 356.445 220.115 11.37 22.55 - 56 417.065 225.28 9.63 12.52 - 75 248.35000000000002 203.805 14.22 17.63 - 75 341.65500000000003 207.865 9.73 16.73 - 60 383.99 275.685 125.56 88.93 + 58 0.389578125 0.4161032863849765 0.038593749999999996 0.16314553990610328 + 62 0.127640625 0.5051525821596244 0.23331249999999998 0.22269953051643193 + 62 0.9341953125 0.583462441314554 0.127109375 0.18481220657276995 + 56 0.60465625 0.6325469483568076 0.0875 0.24138497652582158 + 56 0.5025078125 0.6273239436619719 0.096609375 0.2311737089201878 + 56 0.6691953125 0.6189906103286384 0.047140625000000005 0.19098591549295774 + 56 0.512796875 0.5282511737089202 0.03371875 0.02720657276995305 + 0 0.6864453125 0.5319600938967136 0.082890625 0.3239671361502347 + 0 0.612484375 0.4461971830985916 0.023625 0.08389671361502347 + 68 0.811859375 0.5017253521126761 0.02303125 0.037488262910798126 + 72 0.7863203125 0.5363732394366197 0.031703125 0.2542488262910798 + 73 0.9561562499999999 0.7717018779342724 0.02240625 0.10730046948356808 + 73 0.96825 0.7780751173708921 0.020125 0.10901408450704225 + 74 0.7105546875 0.31 0.021828125 0.05136150234741784 + 75 0.8865624999999999 0.8316079812206573 0.0573125 0.2104929577464789 + 75 0.5569453125 0.5167018779342724 0.017765625 0.05293427230046949 + 56 0.6516640625 0.5288262910798122 0.015046875000000001 0.029389671361502348 + 75 0.388046875 0.4784154929577465 0.022218750000000002 0.04138497652582159 + 75 0.5338359375 0.48794600938967136 0.015203125000000001 0.039272300469483566 + 60 0.599984375 0.6471478873239437 0.19618750000000001 0.20875586854460096 + ```
diff --git a/tools/open_dataset_tool/coco2017.py b/tools/open_dataset_tool/coco2017.py index d3add4750..17d00ead7 100644 --- a/tools/open_dataset_tool/coco2017.py +++ b/tools/open_dataset_tool/coco2017.py @@ -27,6 +27,14 @@ def txtywh2cxcywh(top_left_x, top_left_y, width, height): return cx, cy, w, h +def cxcywh2cxcywhn(cx, cy, w, h, img_w, img_h): + cx = cx / img_w + cy = cy / img_h + w = w / img_w + h = h / img_h + return cx, cy, w, h + + if __name__ == '__main__': # Set argument (data directory) parser = argparse.ArgumentParser(description="Parser for coco2017 dataset downloader.") @@ -59,18 +67,25 @@ def txtywh2cxcywh(top_left_x, top_left_y, width, height): # Unzip train images print('Unzip training images zip file ...') - train_images_dir = coco2017_path / 'images' - shutil.unpack_archive(train_images_download_path, train_images_dir, "zip") + images_dir = coco2017_path / 'images' + shutil.unpack_archive(train_images_download_path, images_dir, "zip") print('Rename train2017 to train') - os.rename(train_images_dir / 'train2017', train_images_dir / 'train') + try: # Remove already exists one + shutil.rmtree(images_dir / 'train') + except OSError as e: + print(e) + os.rename(images_dir / 'train2017', images_dir / 'train') print('Done!') # Unzip valid images print('Unzip training images zip file ...') - valid_images_dir = coco2017_path / 'images' - shutil.unpack_archive(valid_images_download_path, valid_images_dir, "zip") + shutil.unpack_archive(valid_images_download_path, images_dir, "zip") print('Rename val2017 to valid') - os.rename(train_images_dir / 'val2017', train_images_dir / 'valid') + try: # Remove already exists one + shutil.rmtree(images_dir / 'valid') + except OSError as e: + print(e) + os.rename(images_dir / 'val2017', images_dir / 'valid') print('Done!') # Unzip annotation zip file @@ -94,6 +109,7 @@ def txtywh2cxcywh(top_left_x, top_left_y, width, height): CLASS91_LABEL_TO_NAME[item['id']] = item['name'] train_annotations = {image_info['id']: [image_info['file_name']] for image_info in train_ann_json['images']} + train_imgid_to_info = {info['id']: info for info in train_ann_json['images']} for ann in tqdm(train_ann_json['annotations']): image_id = ann['image_id'] @@ -103,6 +119,7 @@ def txtywh2cxcywh(top_left_x, top_left_y, width, height): # TODO: Support various box type e.g. xyxy top_left_x, top_left_y, width, height = ann['bbox'] cx, cy, w, h = txtywh2cxcywh(top_left_x, top_left_y, width, height) + cx, cy, w, h = cxcywh2cxcywhn(cx, cy, w, h, train_imgid_to_info[image_id]['width'], train_imgid_to_info[image_id]['height']) instance = [label, cx, cy, w, h] train_annotations[image_id].append(instance) @@ -128,6 +145,7 @@ def txtywh2cxcywh(top_left_x, top_left_y, width, height): valid_ann_json = json.load(f) valid_annotations = {image_info['id']: [image_info['file_name']] for image_info in valid_ann_json['images']} + valid_imgid_to_info = {info['id']: info for info in valid_ann_json['images']} for ann in tqdm(valid_ann_json['annotations']): image_id = ann['image_id'] @@ -137,6 +155,7 @@ def txtywh2cxcywh(top_left_x, top_left_y, width, height): # TODO: Support various box type e.g. xyxy top_left_x, top_left_y, width, height = ann['bbox'] cx, cy, w, h = txtywh2cxcywh(top_left_x, top_left_y, width, height) + cx, cy, w, h = cxcywh2cxcywhn(cx, cy, w, h, valid_imgid_to_info[image_id]['width'], valid_imgid_to_info[image_id]['height']) instance = [label, cx, cy, w, h] valid_annotations[image_id].append(instance) From 0ae649b0b072921aed750cacca74eaa7e47ca902 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Mon, 22 Apr 2024 13:39:35 +0000 Subject: [PATCH 57/91] Add huggingface cifar100.yaml --- config/data/huggingface/cifar100.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 config/data/huggingface/cifar100.yaml diff --git a/config/data/huggingface/cifar100.yaml b/config/data/huggingface/cifar100.yaml new file mode 100644 index 000000000..677564170 --- /dev/null +++ b/config/data/huggingface/cifar100.yaml @@ -0,0 +1,11 @@ +data: + name: cifar100 + task: classification + format: huggingface + metadata: + custom_cache_dir: ./data/huggingface + repo: cifar100 + subset: ~ + features: + image: img + label: fine_label \ No newline at end of file From 7349e75eaa69d18064df90d2fba35132e68dd9ea Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Mon, 22 Apr 2024 13:43:23 +0000 Subject: [PATCH 58/91] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85d60d11b..ef0a8e2a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## New Features: - Add dataset validation step and refactoring data modules by `@illian01` in [PR 417](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/417), [PR 419](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/419) +- Add various dataset examples including automatic open dataset format converter by `@illian01` in [PR 430](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/430) ## Bug Fixes: From de7ff19927ae557e165dd3f15d4b0743b2aeb468 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 23 Apr 2024 02:09:19 +0000 Subject: [PATCH 59/91] Minor docs update --- docs/components/data.md | 9 +++------ docs/getting_started/dataset_preparation/huggingface.md | 8 ++++---- docs/getting_started/dataset_preparation/local.md | 8 ++++---- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/docs/components/data.md b/docs/components/data.md index 7899af582..a99659979 100644 --- a/docs/components/data.md +++ b/docs/components/data.md @@ -30,11 +30,8 @@ This structure should be reflected in your configuration file under the respecti | `data.format` | **`local`** as an identifier of dataset format. | | `data.path.root` | (str) Root directory of dataset. | | `data.path.train.image` | (str) The directory for training images. Should be **relative** path to root directory. | -| `data.path.train.label` | (str) The directory for training labels or label file (depends on the task). This should be **relative** path to root directory. | | `data.path.valid.image` | (str) The directory for validation images. Should be **relative** path to root directory. | -| `data.path.valid.label` | (str) The directory for validation labels or label file (depends on the task). This should be **relative** path to root directory. | | `data.path.test.image` | (str) The directory for test images. Should be **relative** path to root directory. | -| `data.path.test.label` | (str) The directory for test labels or label file (depends on the task). This should be **relative** path to root directory. | ### Image classification @@ -47,9 +44,9 @@ To train an image classification model using NetsPresso Trainer, **users must or | Field | Description | |---|---| | `data.id_mapping` | (list) Class list for each class index. | -| `data.path.train.label` | (str) For classificaiton, label field must be path of .csv file. This should be **relative** path to root directory. | -| `data.path.valid.label` | (str) For classificaiton, label field must be path of .csv file. This should be **relative** path to root directory. | -| `data.path.test.label` | (str) For classificaiton, label field must be path of .csv file. This should be **relative** path to root directory. | +| `data.path.train.label` | (str) For classificaiton, label field must be path of `.csv` file. This should be **relative** path to root directory. | +| `data.path.valid.label` | (str) For classificaiton, label field must be path of `.csv` file. This should be **relative** path to root directory. | +| `data.path.test.label` | (str) For classificaiton, label field must be path of `.csv` file. This should be **relative** path to root directory. |
Data hierarchy example - ImageNet1K diff --git a/docs/getting_started/dataset_preparation/huggingface.md b/docs/getting_started/dataset_preparation/huggingface.md index 821188fdb..627e9b1d4 100644 --- a/docs/getting_started/dataset_preparation/huggingface.md +++ b/docs/getting_started/dataset_preparation/huggingface.md @@ -1,6 +1,6 @@ # Data preparation (Hugging Face) -The Hugging Face datasets offers a vast array of datasets to support various tasks, making them readily accessible through a user-friendly API. Provided datasets in Hugging Face datasets are typically structured into `training`, `validation`, and `testing` sets. This structure allows NetsPresso Trainer to utilize various datasets with yaml configuration. +The Hugging Face datasets offers a vast array of datasets to support various tasks, making them readily accessible through a user-friendly API. Provided datasets by Hugging Face datasets are typically structured into `training`, `validation`, and `testing` sets. This structure allows NetsPresso Trainer to utilize various datasets with yaml configuration. To explore official Hugging Face datasets catalogue, please refer to the [hugging Face datasets page](https://huggingface.co/datasets). @@ -36,9 +36,9 @@ data: ## Agreement the conditions to access the datasets -Some datasets are publicly available, but require a agreement to use. For example, if you want to use [ImageNet1K](https://huggingface.co/datasets/imagenet-1k) in Hugging Face datasets, you have to log in to Hugging Face homepage and agree on the conditions. +Some datasets are publicly available, but may require a agreement to be used. For instance, to use [ImageNet1K](https://huggingface.co/datasets/imagenet-1k) in Hugging Face datasets, you have to log in to Hugging Face homepage and accpet the conditions. -Make sure to agree the conditions at Hugging Face website, and log in to huggingface-cli before you start. +Make sure that you agreed to the conditions on Hugging Face website, and log in to `huggingface-cli` before you start. ```bash huggingface-cli login @@ -66,7 +66,7 @@ data: ## Set features -You can check features of dataset in Hugging Face homepage. If you see [CIFAR100](https://huggingface.co/datasets/cifar100), there are three features in the dataset which are `img`, `fine_label`, `coarse_label`. Since image data is named as `img` and 100-class label is named as `fine_label`, we fill out data configuration as below. +You should check features of dataset in Hugging Face homepage. If you see [CIFAR100](https://huggingface.co/datasets/cifar100), there are three features in the dataset which are `img`, `fine_label`, `coarse_label`. In this dataset, the image data is denoted by `img` and the labels for the 100 classes are represented by `fine_label`. Given this structure, the data configuration should be filled out as below. ```yaml data: diff --git a/docs/getting_started/dataset_preparation/local.md b/docs/getting_started/dataset_preparation/local.md index 835dfc705..381f74d5f 100644 --- a/docs/getting_started/dataset_preparation/local.md +++ b/docs/getting_started/dataset_preparation/local.md @@ -39,8 +39,8 @@ Place your images on proper path. Set labels on proper path. -- For image classification, you may need image files and a corresponding label file (usually in csv format). -- For semantic segmentation and object detection, organize your images and label files (could be masks or box annotations) in corresponding folders. +- For image classification, you may need csv format label files. +- For semantic segmentation and object detection, organize your label files (could be masks or box annotations) in corresponding folders. ```text /my_dataset @@ -69,7 +69,7 @@ Set labels on proper path. ### Set configuration file -Define the paths to your datasets in the configuration file to tell NetsPresso Trainer where to find the data. Here is example for classification: +Define the paths to your datasets in the configuration file to tell NetsPresso Trainer where to find the data. Finally, you can complete data configuration by adding some metadata like `id_mapping`. Here is example for classification: ```yaml data: @@ -94,7 +94,7 @@ For detailed definition of data configuration, please refer to [components/data] ## Open datasets -If you are interested in utilizing open datasets, you can use them by following the instructions. These instructions automatically set dataset as local custom datasets format. +If you are interested in using open datasets, follow the instructions below to seamlessly integrate them into the local custom datasets format. ### Image classification From a78e7c560de5fdcf2eb0311a67dc4debeb898ee6 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 23 Apr 2024 07:47:49 +0000 Subject: [PATCH 60/91] Update classification load_id_mapping --- .../dataloaders/classification.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/netspresso_trainer/dataloaders/classification.py b/src/netspresso_trainer/dataloaders/classification.py index 8925f3c1a..47021708e 100644 --- a/src/netspresso_trainer/dataloaders/classification.py +++ b/src/netspresso_trainer/dataloaders/classification.py @@ -3,6 +3,8 @@ from multiprocessing.pool import ThreadPool from pathlib import Path from typing import Dict, List, Optional, Tuple, Union +from omegaconf import ListConfig +import os import PIL.Image as Image import torch.distributed as dist @@ -45,7 +47,22 @@ def load_data(self, split='train'): return images_and_targets def load_id_mapping(self): - return list(self.conf_data.id_mapping) + root_path = Path(self.conf_data.path.root) + + if isinstance(self.conf_data.id_mapping, ListConfig): + return list(self.conf_data.id_mapping) + + elif isinstance(self.conf_data.id_mapping, str): + id_mapping_path = root_path / self.conf_data.id_mapping + if not os.path.isfile(id_mapping_path): + raise ValueError(f"Cannot find file {id_mapping_path}") + + with open(id_mapping_path, 'r') as f: + lines = f.readlines() + return [line.strip() for line in lines] + + else: + raise ValueError(f"Unsupported id_mapping value {self.conf_data.id_mapping}") def load_class_map(self, id_mapping): idx_to_class: Dict[int, str] = dict(enumerate(id_mapping)) From 6b4dfcf9d2331d0d7f150b39e335c297ca34a2e4 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 23 Apr 2024 07:47:56 +0000 Subject: [PATCH 61/91] Update detection load_id_mapping --- .../dataloaders/detection.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/netspresso_trainer/dataloaders/detection.py b/src/netspresso_trainer/dataloaders/detection.py index b4289e327..3d4edb37c 100644 --- a/src/netspresso_trainer/dataloaders/detection.py +++ b/src/netspresso_trainer/dataloaders/detection.py @@ -3,6 +3,8 @@ from multiprocessing.pool import ThreadPool from pathlib import Path from typing import Dict, List, Optional, Tuple, Union +from omegaconf import ListConfig +import os import numpy as np import PIL.Image as Image @@ -51,7 +53,22 @@ def load_data(self, split='train'): return images_and_targets def load_id_mapping(self): - return list(self.conf_data.id_mapping) + root_path = Path(self.conf_data.path.root) + + if isinstance(self.conf_data.id_mapping, ListConfig): + return list(self.conf_data.id_mapping) + + elif isinstance(self.conf_data.id_mapping, str): + id_mapping_path = root_path / self.conf_data.id_mapping + if not os.path.isfile(id_mapping_path): + raise ValueError(f"Cannot find file {id_mapping_path}") + + with open(id_mapping_path, 'r') as f: + lines = f.readlines() + return [line.strip() for line in lines] + + else: + raise ValueError(f"Unsupported id_mapping value {self.conf_data.id_mapping}") def load_class_map(self, id_mapping): idx_to_class: Dict[int, str] = dict(enumerate(id_mapping)) From ce39e1fe1a70fad7f2bfc9cbae96083eff1d6afd Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Thu, 25 Apr 2024 01:27:37 +0000 Subject: [PATCH 62/91] Fix segmentation load_class_map return --- src/netspresso_trainer/dataloaders/segmentation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/netspresso_trainer/dataloaders/segmentation.py b/src/netspresso_trainer/dataloaders/segmentation.py index 814253df2..15c990b27 100644 --- a/src/netspresso_trainer/dataloaders/segmentation.py +++ b/src/netspresso_trainer/dataloaders/segmentation.py @@ -56,7 +56,7 @@ def load_class_map(self, id_mapping): assert isinstance(id_mapping[0], str), f"Unknown type for class name! {type(id_mapping[0])}" idx_to_class: Dict[int, str] = dict(enumerate(id_mapping)) label_value_to_idx = {k: k for k in idx_to_class} - return idx_to_class, label_value_to_idx + return {'idx_to_class': idx_to_class, 'label_value_to_idx': label_value_to_idx} idx_to_class: Dict[int, str] = {} label_value_to_idx: Dict[Union[int, Tuple], int] = {} From f3035c0548728f80eaced504f4cd5ab120730097 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Thu, 25 Apr 2024 01:27:50 +0000 Subject: [PATCH 63/91] Add TODO for pose_estimation --- src/netspresso_trainer/dataloaders/pose_estimation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/netspresso_trainer/dataloaders/pose_estimation.py b/src/netspresso_trainer/dataloaders/pose_estimation.py index 806d4503a..ade735317 100644 --- a/src/netspresso_trainer/dataloaders/pose_estimation.py +++ b/src/netspresso_trainer/dataloaders/pose_estimation.py @@ -50,6 +50,7 @@ def load_data(self, split='train'): return images_and_targets def load_id_mapping(self): + # TODO: Get id_mapping from txt file return list(self.conf_data.id_mapping) def load_class_map(self, id_mapping): From b167d811a767afb72e23487a6906dd35cd2d6bb9 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Thu, 25 Apr 2024 01:29:06 +0000 Subject: [PATCH 64/91] Save id_mapping.txt --- tools/open_dataset_tool/cifar100.py | 2 +- tools/open_dataset_tool/coco2017.py | 7 +++++++ tools/open_dataset_tool/imagenet1k.py | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/tools/open_dataset_tool/cifar100.py b/tools/open_dataset_tool/cifar100.py index 4d99b97e8..1bb17ab6b 100644 --- a/tools/open_dataset_tool/cifar100.py +++ b/tools/open_dataset_tool/cifar100.py @@ -98,7 +98,7 @@ def unpickle(file): # Build id_mapping id_mapping = CIFAR100_CLASSES - with open(data_dir / 'id_mapping', 'w') as f: + with open(data_dir / 'id_mapping.txt', 'w') as f: f.write('\n'.join(id_mapping)) f.close() diff --git a/tools/open_dataset_tool/coco2017.py b/tools/open_dataset_tool/coco2017.py index 17d00ead7..70adf2b32 100644 --- a/tools/open_dataset_tool/coco2017.py +++ b/tools/open_dataset_tool/coco2017.py @@ -17,6 +17,7 @@ VALID_IMAGES_URL = 'http://images.cocodataset.org/zips/val2017.zip' ANNOTATION_URL = 'http://images.cocodataset.org/annotations/annotations_trainval2017.zip' CLASS80_NAME_TO_LABEL = {'person': 0, 'bicycle': 1, 'car': 2, 'motorcycle': 3, 'airplane': 4, 'bus': 5, 'train': 6, 'truck': 7, 'boat': 8, 'traffic light': 9, 'fire hydrant': 10, 'stop sign': 11, 'parking meter': 12, 'bench': 13, 'bird': 14, 'cat': 15, 'dog': 16, 'horse': 17, 'sheep': 18, 'cow': 19, 'elephant': 20, 'bear': 21, 'zebra': 22, 'giraffe': 23, 'backpack': 24, 'umbrella': 25, 'handbag': 26, 'tie': 27, 'suitcase': 28, 'frisbee': 29, 'skis': 30, 'snowboard': 31, 'sports ball': 32, 'kite': 33, 'baseball bat': 34, 'baseball glove': 35, 'skateboard': 36, 'surfboard': 37, 'tennis racket': 38, 'bottle': 39, 'wine glass': 40, 'cup': 41, 'fork': 42, 'knife': 43, 'spoon': 44, 'bowl': 45, 'banana': 46, 'apple': 47, 'sandwich': 48, 'orange': 49, 'broccoli': 50, 'carrot': 51, 'hot dog': 52, 'pizza': 53, 'donut': 54, 'cake': 55, 'chair': 56, 'couch': 57, 'potted plant': 58, 'bed': 59, 'dining table': 60, 'toilet': 61, 'tv': 62, 'laptop': 63, 'mouse': 64, 'remote': 65, 'keyboard': 66, 'cell phone': 67, 'microwave': 68, 'oven': 69, 'toaster': 70, 'sink': 71, 'refrigerator': 72, 'book': 73, 'clock': 74, 'vase': 75, 'scissors': 76, 'teddy bear': 77, 'hair drier': 78, 'toothbrush': 79} +CLASS80_LABEL_TO_NAME = {val: key for key, val in CLASS80_NAME_TO_LABEL.items()} def txtywh2cxcywh(top_left_x, top_left_y, width, height): @@ -171,6 +172,12 @@ def cxcywh2cxcywhn(cx, cy, w, h, img_w, img_h): with open((valid_label_dir / file_name).with_suffix('.txt'), 'w') as f: f.write(texts) + # Build id_mapping + id_mapping = [CLASS80_LABEL_TO_NAME[i] for i in range(80)] + with open(coco2017_path / 'id_mapping.txt', 'w') as f: + f.write('\n'.join(id_mapping)) + f.close() + try: shutil.rmtree(coco2017_path / 'annotations') except OSError as e: diff --git a/tools/open_dataset_tool/imagenet1k.py b/tools/open_dataset_tool/imagenet1k.py index 2ffb3d3ca..72480d270 100644 --- a/tools/open_dataset_tool/imagenet1k.py +++ b/tools/open_dataset_tool/imagenet1k.py @@ -129,7 +129,7 @@ # Build id_mapping print('Building id_mapping ...') id_mapping = [cls_to_name[i] for i in range(1000)] - with open(imagenet_path / 'id_mapping', 'w') as f: + with open(imagenet_path / 'id_mapping.txt', 'w') as f: f.write('\n'.join(id_mapping)) f.close() print('Done!') From ceb0130d5cf2ce2b724db958e0dbefac0b11116e Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Thu, 25 Apr 2024 01:30:43 +0000 Subject: [PATCH 65/91] Update config --- config/data/local/cifar100.yaml | 5 +++-- config/data/local/coco2017.yaml | 3 ++- config/data/local/imagenet1k.yaml | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/config/data/local/cifar100.yaml b/config/data/local/cifar100.yaml index d90efb951..c1b53bda1 100644 --- a/config/data/local/cifar100.yaml +++ b/config/data/local/cifar100.yaml @@ -3,7 +3,7 @@ data: task: classification format: local path: - root: ./data/cifar-100 # dataset root + root: ./data/cifar100 # dataset root train: image: images/train # directory for training images label: labels/cifar100_train.csv # directory for training labels or csv file @@ -13,4 +13,5 @@ data: test: image: ~ label: ~ - id_mapping: ['apple', 'aquarium_fish', 'baby', 'bear', 'beaver', 'bed', 'bee', 'beetle', 'bicycle', 'bottle', 'bowl', 'boy', 'bridge', 'bus', 'butterfly', 'camel', 'can', 'castle', 'caterpillar', 'cattle', 'chair', 'chimpanzee', 'clock', 'cloud', 'cockroach', 'couch', 'crab', 'crocodile', 'cup', 'dinosaur', 'dolphin', 'elephant', 'flatfish', 'forest', 'fox', 'girl', 'hamster', 'house', 'kangaroo', 'keyboard', 'lamp', 'lawn_mower', 'leopard', 'lion', 'lizard', 'lobster', 'man', 'maple_tree', 'motorcycle', 'mountain', 'mouse', 'mushroom', 'oak_tree', 'orange', 'orchid', 'otter', 'palm_tree', 'pear', 'pickup_truck', 'pine_tree', 'plain', 'plate', 'poppy', 'porcupine', 'possum', 'rabbit', 'raccoon', 'ray', 'road', 'rocket', 'rose', 'sea', 'seal', 'shark', 'shrew', 'skunk', 'skyscraper', 'snail', 'snake', 'spider', 'squirrel', 'streetcar', 'sunflower', 'sweet_pepper', 'table', 'tank', 'telephone', 'television', 'tiger', 'tractor', 'train', 'trout', 'tulip', 'turtle', 'wardrobe', 'whale', 'willow_tree', 'wolf', 'woman', 'worm'] \ No newline at end of file + id_mapping: id_mapping.txt + # id_mapping: ['apple', 'aquarium_fish', 'baby', 'bear', 'beaver', 'bed', 'bee', 'beetle', 'bicycle', 'bottle', 'bowl', 'boy', 'bridge', 'bus', 'butterfly', 'camel', 'can', 'castle', 'caterpillar', 'cattle', 'chair', 'chimpanzee', 'clock', 'cloud', 'cockroach', 'couch', 'crab', 'crocodile', 'cup', 'dinosaur', 'dolphin', 'elephant', 'flatfish', 'forest', 'fox', 'girl', 'hamster', 'house', 'kangaroo', 'keyboard', 'lamp', 'lawn_mower', 'leopard', 'lion', 'lizard', 'lobster', 'man', 'maple_tree', 'motorcycle', 'mountain', 'mouse', 'mushroom', 'oak_tree', 'orange', 'orchid', 'otter', 'palm_tree', 'pear', 'pickup_truck', 'pine_tree', 'plain', 'plate', 'poppy', 'porcupine', 'possum', 'rabbit', 'raccoon', 'ray', 'road', 'rocket', 'rose', 'sea', 'seal', 'shark', 'shrew', 'skunk', 'skyscraper', 'snail', 'snake', 'spider', 'squirrel', 'streetcar', 'sunflower', 'sweet_pepper', 'table', 'tank', 'telephone', 'television', 'tiger', 'tractor', 'train', 'trout', 'tulip', 'turtle', 'wardrobe', 'whale', 'willow_tree', 'wolf', 'woman', 'worm'] \ No newline at end of file diff --git a/config/data/local/coco2017.yaml b/config/data/local/coco2017.yaml index fc6d969b0..56143ede4 100644 --- a/config/data/local/coco2017.yaml +++ b/config/data/local/coco2017.yaml @@ -16,5 +16,6 @@ data: pattern: image: ~ label: ~ - id_mapping: ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] + id_mapping: id_mapping.txt + # id_mapping: ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] pallete: ~ diff --git a/config/data/local/imagenet1k.yaml b/config/data/local/imagenet1k.yaml index b5809ce80..62e419fda 100644 --- a/config/data/local/imagenet1k.yaml +++ b/config/data/local/imagenet1k.yaml @@ -13,4 +13,5 @@ data: test: image: ~ label: ~ - id_mapping: ['kit fox', 'English setter', 'Siberian husky', 'Australian terrier', 'English springer', 'grey whale', 'lesser panda', 'Egyptian cat', 'ibex', 'Persian cat', 'cougar', 'gazelle', 'porcupine', 'sea lion', 'malamute', 'badger', 'Great Dane', 'Walker hound', 'Welsh springer spaniel', 'whippet', 'Scottish deerhound', 'killer whale', 'mink', 'African elephant', 'Weimaraner', 'soft-coated wheaten terrier', 'Dandie Dinmont', 'red wolf', 'Old English sheepdog', 'jaguar', 'otterhound', 'bloodhound', 'Airedale', 'hyena', 'meerkat', 'giant schnauzer', 'titi', 'three-toed sloth', 'sorrel', 'black-footed ferret', 'dalmatian', 'black-and-tan coonhound', 'papillon', 'skunk', 'Staffordshire bullterrier', 'Mexican hairless', 'Bouvier des Flandres', 'weasel', 'miniature poodle', 'Cardigan', 'malinois', 'bighorn', 'fox squirrel', 'colobus', 'tiger cat', 'Lhasa', 'impala', 'coyote', 'Yorkshire terrier', 'Newfoundland', 'brown bear', 'red fox', 'Norwegian elkhound', 'Rottweiler', 'hartebeest', 'Saluki', 'grey fox', 'schipperke', 'Pekinese', 'Brabancon griffon', 'West Highland white terrier', 'Sealyham terrier', 'guenon', 'mongoose', 'indri', 'tiger', 'Irish wolfhound', 'wild boar', 'EntleBucher', 'zebra', 'ram', 'French bulldog', 'orangutan', 'basenji', 'leopard', 'Bernese mountain dog', 'Maltese dog', 'Norfolk terrier', 'toy terrier', 'vizsla', 'cairn', 'squirrel monkey', 'groenendael', 'clumber', 'Siamese cat', 'chimpanzee', 'komondor', 'Afghan hound', 'Japanese spaniel', 'proboscis monkey', 'guinea pig', 'white wolf', 'ice bear', 'gorilla', 'borzoi', 'toy poodle', 'Kerry blue terrier', 'ox', 'Scotch terrier', 'Tibetan mastiff', 'spider monkey', 'Doberman', 'Boston bull', 'Greater Swiss Mountain dog', 'Appenzeller', 'Shih-Tzu', 'Irish water spaniel', 'Pomeranian', 'Bedlington terrier', 'warthog', 'Arabian camel', 'siamang', 'miniature schnauzer', 'collie', 'golden retriever', 'Irish terrier', 'affenpinscher', 'Border collie', 'hare', 'boxer', 'silky terrier', 'beagle', 'Leonberg', 'German short-haired pointer', 'patas', 'dhole', 'baboon', 'macaque', 'Chesapeake Bay retriever', 'bull mastiff', 'kuvasz', 'capuchin', 'pug', 'curly-coated retriever', 'Norwich terrier', 'flat-coated retriever', 'hog', 'keeshond', 'Eskimo dog', 'Brittany spaniel', 'standard poodle', 'Lakeland terrier', 'snow leopard', 'Gordon setter', 'dingo', 'standard schnauzer', 'hamster', 'Tibetan terrier', 'Arctic fox', 'wire-haired fox terrier', 'basset', 'water buffalo', 'American black bear', 'Angora', 'bison', 'howler monkey', 'hippopotamus', 'chow', 'giant panda', 'American Staffordshire terrier', 'Shetland sheepdog', 'Great Pyrenees', 'Chihuahua', 'tabby', 'marmoset', 'Labrador retriever', 'Saint Bernard', 'armadillo', 'Samoyed', 'bluetick', 'redbone', 'polecat', 'marmot', 'kelpie', 'gibbon', 'llama', 'miniature pinscher', 'wood rabbit', 'Italian greyhound', 'lion', 'cocker spaniel', 'Irish setter', 'dugong', 'Indian elephant', 'beaver', 'Sussex spaniel', 'Pembroke', 'Blenheim spaniel', 'Madagascar cat', 'Rhodesian ridgeback', 'lynx', 'African hunting dog', 'langur', 'Ibizan hound', 'timber wolf', 'cheetah', 'English foxhound', 'briard', 'sloth bear', 'Border terrier', 'German shepherd', 'otter', 'koala', 'tusker', 'echidna', 'wallaby', 'platypus', 'wombat', 'revolver', 'umbrella', 'schooner', 'soccer ball', 'accordion', 'ant', 'starfish', 'chambered nautilus', 'grand piano', 'laptop', 'strawberry', 'airliner', 'warplane', 'airship', 'balloon', 'space shuttle', 'fireboat', 'gondola', 'speedboat', 'lifeboat', 'canoe', 'yawl', 'catamaran', 'trimaran', 'container ship', 'liner', 'pirate', 'aircraft carrier', 'submarine', 'wreck', 'half track', 'tank', 'missile', 'bobsled', 'dogsled', 'bicycle-built-for-two', 'mountain bike', 'freight car', 'passenger car', 'barrow', 'shopping cart', 'motor scooter', 'forklift', 'electric locomotive', 'steam locomotive', 'amphibian', 'ambulance', 'beach wagon', 'cab', 'convertible', 'jeep', 'limousine', 'minivan', 'Model T', 'racer', 'sports car', 'go-kart', 'golfcart', 'moped', 'snowplow', 'fire engine', 'garbage truck', 'pickup', 'tow truck', 'trailer truck', 'moving van', 'police van', 'recreational vehicle', 'streetcar', 'snowmobile', 'tractor', 'mobile home', 'tricycle', 'unicycle', 'horse cart', 'jinrikisha', 'oxcart', 'bassinet', 'cradle', 'crib', 'four-poster', 'bookcase', 'china cabinet', 'medicine chest', 'chiffonier', 'table lamp', 'file', 'park bench', 'barber chair', 'throne', 'folding chair', 'rocking chair', 'studio couch', 'toilet seat', 'desk', 'pool table', 'dining table', 'entertainment center', 'wardrobe', 'Granny Smith', 'orange', 'lemon', 'fig', 'pineapple', 'banana', 'jackfruit', 'custard apple', 'pomegranate', 'acorn', 'hip', 'ear', 'rapeseed', 'corn', 'buckeye', 'organ', 'upright', 'chime', 'drum', 'gong', 'maraca', 'marimba', 'steel drum', 'banjo', 'cello', 'violin', 'harp', 'acoustic guitar', 'electric guitar', 'cornet', 'French horn', 'trombone', 'harmonica', 'ocarina', 'panpipe', 'bassoon', 'oboe', 'sax', 'flute', 'daisy', "yellow lady's slipper", 'cliff', 'valley', 'alp', 'volcano', 'promontory', 'sandbar', 'coral reef', 'lakeside', 'seashore', 'geyser', 'hatchet', 'cleaver', 'letter opener', 'plane', 'power drill', 'lawn mower', 'hammer', 'corkscrew', 'can opener', 'plunger', 'screwdriver', 'shovel', 'plow', 'chain saw', 'cock', 'hen', 'ostrich', 'brambling', 'goldfinch', 'house finch', 'junco', 'indigo bunting', 'robin', 'bulbul', 'jay', 'magpie', 'chickadee', 'water ouzel', 'kite', 'bald eagle', 'vulture', 'great grey owl', 'black grouse', 'ptarmigan', 'ruffed grouse', 'prairie chicken', 'peacock', 'quail', 'partridge', 'African grey', 'macaw', 'sulphur-crested cockatoo', 'lorikeet', 'coucal', 'bee eater', 'hornbill', 'hummingbird', 'jacamar', 'toucan', 'drake', 'red-breasted merganser', 'goose', 'black swan', 'white stork', 'black stork', 'spoonbill', 'flamingo', 'American egret', 'little blue heron', 'bittern', 'crane', 'limpkin', 'American coot', 'bustard', 'ruddy turnstone', 'red-backed sandpiper', 'redshank', 'dowitcher', 'oystercatcher', 'European gallinule', 'pelican', 'king penguin', 'albatross', 'great white shark', 'tiger shark', 'hammerhead', 'electric ray', 'stingray', 'barracouta', 'coho', 'tench', 'goldfish', 'eel', 'rock beauty', 'anemone fish', 'lionfish', 'puffer', 'sturgeon', 'gar', 'loggerhead', 'leatherback turtle', 'mud turtle', 'terrapin', 'box turtle', 'banded gecko', 'common iguana', 'American chameleon', 'whiptail', 'agama', 'frilled lizard', 'alligator lizard', 'Gila monster', 'green lizard', 'African chameleon', 'Komodo dragon', 'triceratops', 'African crocodile', 'American alligator', 'thunder snake', 'ringneck snake', 'hognose snake', 'green snake', 'king snake', 'garter snake', 'water snake', 'vine snake', 'night snake', 'boa constrictor', 'rock python', 'Indian cobra', 'green mamba', 'sea snake', 'horned viper', 'diamondback', 'sidewinder', 'European fire salamander', 'common newt', 'eft', 'spotted salamander', 'axolotl', 'bullfrog', 'tree frog', 'tailed frog', 'whistle', 'wing', 'paintbrush', 'hand blower', 'oxygen mask', 'snorkel', 'loudspeaker', 'microphone', 'screen', 'mouse', 'electric fan', 'oil filter', 'strainer', 'space heater', 'stove', 'guillotine', 'barometer', 'rule', 'odometer', 'scale', 'analog clock', 'digital clock', 'wall clock', 'hourglass', 'sundial', 'parking meter', 'stopwatch', 'digital watch', 'stethoscope', 'syringe', 'magnetic compass', 'binoculars', 'projector', 'sunglasses', 'loupe', 'radio telescope', 'bow', 'cannon', 'assault rifle', 'rifle', 'projectile', 'computer keyboard', 'typewriter keyboard', 'crane', 'lighter', 'abacus', 'cash machine', 'slide rule', 'desktop computer', 'hand-held computer', 'notebook', 'web site', 'harvester', 'thresher', 'printer', 'slot', 'vending machine', 'sewing machine', 'joystick', 'switch', 'hook', 'car wheel', 'paddlewheel', 'pinwheel', "potter's wheel", 'gas pump', 'carousel', 'swing', 'reel', 'radiator', 'puck', 'hard disc', 'sunglass', 'pick', 'car mirror', 'solar dish', 'remote control', 'disk brake', 'buckle', 'hair slide', 'knot', 'combination lock', 'padlock', 'nail', 'safety pin', 'screw', 'muzzle', 'seat belt', 'ski', 'candle', "jack-o'-lantern", 'spotlight', 'torch', 'neck brace', 'pier', 'tripod', 'maypole', 'mousetrap', 'spider web', 'trilobite', 'harvestman', 'scorpion', 'black and gold garden spider', 'barn spider', 'garden spider', 'black widow', 'tarantula', 'wolf spider', 'tick', 'centipede', 'isopod', 'Dungeness crab', 'rock crab', 'fiddler crab', 'king crab', 'American lobster', 'spiny lobster', 'crayfish', 'hermit crab', 'tiger beetle', 'ladybug', 'ground beetle', 'long-horned beetle', 'leaf beetle', 'dung beetle', 'rhinoceros beetle', 'weevil', 'fly', 'bee', 'grasshopper', 'cricket', 'walking stick', 'cockroach', 'mantis', 'cicada', 'leafhopper', 'lacewing', 'dragonfly', 'damselfly', 'admiral', 'ringlet', 'monarch', 'cabbage butterfly', 'sulphur butterfly', 'lycaenid', 'jellyfish', 'sea anemone', 'brain coral', 'flatworm', 'nematode', 'conch', 'snail', 'slug', 'sea slug', 'chiton', 'sea urchin', 'sea cucumber', 'iron', 'espresso maker', 'microwave', 'Dutch oven', 'rotisserie', 'toaster', 'waffle iron', 'vacuum', 'dishwasher', 'refrigerator', 'washer', 'Crock Pot', 'frying pan', 'wok', 'caldron', 'coffeepot', 'teapot', 'spatula', 'altar', 'triumphal arch', 'patio', 'steel arch bridge', 'suspension bridge', 'viaduct', 'barn', 'greenhouse', 'palace', 'monastery', 'library', 'apiary', 'boathouse', 'church', 'mosque', 'stupa', 'planetarium', 'restaurant', 'cinema', 'home theater', 'lumbermill', 'coil', 'obelisk', 'totem pole', 'castle', 'prison', 'grocery store', 'bakery', 'barbershop', 'bookshop', 'butcher shop', 'confectionery', 'shoe shop', 'tobacco shop', 'toyshop', 'fountain', 'cliff dwelling', 'yurt', 'dock', 'brass', 'megalith', 'bannister', 'breakwater', 'dam', 'chainlink fence', 'picket fence', 'worm fence', 'stone wall', 'grille', 'sliding door', 'turnstile', 'mountain tent', 'scoreboard', 'honeycomb', 'plate rack', 'pedestal', 'beacon', 'mashed potato', 'bell pepper', 'head cabbage', 'broccoli', 'cauliflower', 'zucchini', 'spaghetti squash', 'acorn squash', 'butternut squash', 'cucumber', 'artichoke', 'cardoon', 'mushroom', 'shower curtain', 'jean', 'carton', 'handkerchief', 'sandal', 'ashcan', 'safe', 'plate', 'necklace', 'croquet ball', 'fur coat', 'thimble', 'pajama', 'running shoe', 'cocktail shaker', 'chest', 'manhole cover', 'modem', 'tub', 'tray', 'balance beam', 'bagel', 'prayer rug', 'kimono', 'hot pot', 'whiskey jug', 'knee pad', 'book jacket', 'spindle', 'ski mask', 'beer bottle', 'crash helmet', 'bottlecap', 'tile roof', 'mask', 'maillot', 'Petri dish', 'football helmet', 'bathing cap', 'teddy', 'holster', 'pop bottle', 'photocopier', 'vestment', 'crossword puzzle', 'golf ball', 'trifle', 'suit', 'water tower', 'feather boa', 'cloak', 'red wine', 'drumstick', 'shield', 'Christmas stocking', 'hoopskirt', 'menu', 'stage', 'bonnet', 'meat loaf', 'baseball', 'face powder', 'scabbard', 'sunscreen', 'beer glass', 'hen-of-the-woods', 'guacamole', 'lampshade', 'wool', 'hay', 'bow tie', 'mailbag', 'water jug', 'bucket', 'dishrag', 'soup bowl', 'eggnog', 'mortar', 'trench coat', 'paddle', 'chain', 'swab', 'mixing bowl', 'potpie', 'wine bottle', 'shoji', 'bulletproof vest', 'drilling platform', 'binder', 'cardigan', 'sweatshirt', 'pot', 'birdhouse', 'hamper', 'ping-pong ball', 'pencil box', 'pay-phone', 'consomme', 'apron', 'punching bag', 'backpack', 'groom', 'bearskin', 'pencil sharpener', 'broom', 'mosquito net', 'abaya', 'mortarboard', 'poncho', 'crutch', 'Polaroid camera', 'space bar', 'cup', 'racket', 'traffic light', 'quill', 'radio', 'dough', 'cuirass', 'military uniform', 'lipstick', 'shower cap', 'monitor', 'oscilloscope', 'mitten', 'brassiere', 'French loaf', 'vase', 'milk can', 'rugby ball', 'paper towel', 'earthstar', 'envelope', 'miniskirt', 'cowboy hat', 'trolleybus', 'perfume', 'bathtub', 'hotdog', 'coral fungus', 'bullet train', 'pillow', 'toilet tissue', 'cassette', "carpenter's kit", 'ladle', 'stinkhorn', 'lotion', 'hair spray', 'academic gown', 'dome', 'crate', 'wig', 'burrito', 'pill bottle', 'chain mail', 'theater curtain', 'window shade', 'barrel', 'washbasin', 'ballpoint', 'basketball', 'bath towel', 'cowboy boot', 'gown', 'window screen', 'agaric', 'cellular telephone', 'nipple', 'barbell', 'mailbox', 'lab coat', 'fire screen', 'minibus', 'packet', 'maze', 'pole', 'horizontal bar', 'sombrero', 'pickelhaube', 'rain barrel', 'wallet', 'cassette player', 'comic book', 'piggy bank', 'street sign', 'bell cote', 'fountain pen', 'Windsor tie', 'volleyball', 'overskirt', 'sarong', 'purse', 'bolo tie', 'bib', 'parachute', 'sleeping bag', 'television', 'swimming trunks', 'measuring cup', 'espresso', 'pizza', 'breastplate', 'shopping basket', 'wooden spoon', 'saltshaker', 'chocolate sauce', 'ballplayer', 'goblet', 'gyromitra', 'stretcher', 'water bottle', 'dial telephone', 'soap dispenser', 'jersey', 'school bus', 'jigsaw puzzle', 'plastic bag', 'reflex camera', 'diaper', 'Band Aid', 'ice lolly', 'velvet', 'tennis ball', 'gasmask', 'doormat', 'Loafer', 'ice cream', 'pretzel', 'quilt', 'maillot', 'tape player', 'clog', 'iPod', 'bolete', 'scuba diver', 'pitcher', 'matchstick', 'bikini', 'sock', 'CD player', 'lens cap', 'thatch', 'vault', 'beaker', 'bubble', 'cheeseburger', 'parallel bars', 'flagpole', 'coffee mug', 'rubber eraser', 'stole', 'carbonara', 'dumbbell'] \ No newline at end of file + id_mapping: id_mapping.txt + #id_mapping: ['kit fox', 'English setter', 'Siberian husky', 'Australian terrier', 'English springer', 'grey whale', 'lesser panda', 'Egyptian cat', 'ibex', 'Persian cat', 'cougar', 'gazelle', 'porcupine', 'sea lion', 'malamute', 'badger', 'Great Dane', 'Walker hound', 'Welsh springer spaniel', 'whippet', 'Scottish deerhound', 'killer whale', 'mink', 'African elephant', 'Weimaraner', 'soft-coated wheaten terrier', 'Dandie Dinmont', 'red wolf', 'Old English sheepdog', 'jaguar', 'otterhound', 'bloodhound', 'Airedale', 'hyena', 'meerkat', 'giant schnauzer', 'titi', 'three-toed sloth', 'sorrel', 'black-footed ferret', 'dalmatian', 'black-and-tan coonhound', 'papillon', 'skunk', 'Staffordshire bullterrier', 'Mexican hairless', 'Bouvier des Flandres', 'weasel', 'miniature poodle', 'Cardigan', 'malinois', 'bighorn', 'fox squirrel', 'colobus', 'tiger cat', 'Lhasa', 'impala', 'coyote', 'Yorkshire terrier', 'Newfoundland', 'brown bear', 'red fox', 'Norwegian elkhound', 'Rottweiler', 'hartebeest', 'Saluki', 'grey fox', 'schipperke', 'Pekinese', 'Brabancon griffon', 'West Highland white terrier', 'Sealyham terrier', 'guenon', 'mongoose', 'indri', 'tiger', 'Irish wolfhound', 'wild boar', 'EntleBucher', 'zebra', 'ram', 'French bulldog', 'orangutan', 'basenji', 'leopard', 'Bernese mountain dog', 'Maltese dog', 'Norfolk terrier', 'toy terrier', 'vizsla', 'cairn', 'squirrel monkey', 'groenendael', 'clumber', 'Siamese cat', 'chimpanzee', 'komondor', 'Afghan hound', 'Japanese spaniel', 'proboscis monkey', 'guinea pig', 'white wolf', 'ice bear', 'gorilla', 'borzoi', 'toy poodle', 'Kerry blue terrier', 'ox', 'Scotch terrier', 'Tibetan mastiff', 'spider monkey', 'Doberman', 'Boston bull', 'Greater Swiss Mountain dog', 'Appenzeller', 'Shih-Tzu', 'Irish water spaniel', 'Pomeranian', 'Bedlington terrier', 'warthog', 'Arabian camel', 'siamang', 'miniature schnauzer', 'collie', 'golden retriever', 'Irish terrier', 'affenpinscher', 'Border collie', 'hare', 'boxer', 'silky terrier', 'beagle', 'Leonberg', 'German short-haired pointer', 'patas', 'dhole', 'baboon', 'macaque', 'Chesapeake Bay retriever', 'bull mastiff', 'kuvasz', 'capuchin', 'pug', 'curly-coated retriever', 'Norwich terrier', 'flat-coated retriever', 'hog', 'keeshond', 'Eskimo dog', 'Brittany spaniel', 'standard poodle', 'Lakeland terrier', 'snow leopard', 'Gordon setter', 'dingo', 'standard schnauzer', 'hamster', 'Tibetan terrier', 'Arctic fox', 'wire-haired fox terrier', 'basset', 'water buffalo', 'American black bear', 'Angora', 'bison', 'howler monkey', 'hippopotamus', 'chow', 'giant panda', 'American Staffordshire terrier', 'Shetland sheepdog', 'Great Pyrenees', 'Chihuahua', 'tabby', 'marmoset', 'Labrador retriever', 'Saint Bernard', 'armadillo', 'Samoyed', 'bluetick', 'redbone', 'polecat', 'marmot', 'kelpie', 'gibbon', 'llama', 'miniature pinscher', 'wood rabbit', 'Italian greyhound', 'lion', 'cocker spaniel', 'Irish setter', 'dugong', 'Indian elephant', 'beaver', 'Sussex spaniel', 'Pembroke', 'Blenheim spaniel', 'Madagascar cat', 'Rhodesian ridgeback', 'lynx', 'African hunting dog', 'langur', 'Ibizan hound', 'timber wolf', 'cheetah', 'English foxhound', 'briard', 'sloth bear', 'Border terrier', 'German shepherd', 'otter', 'koala', 'tusker', 'echidna', 'wallaby', 'platypus', 'wombat', 'revolver', 'umbrella', 'schooner', 'soccer ball', 'accordion', 'ant', 'starfish', 'chambered nautilus', 'grand piano', 'laptop', 'strawberry', 'airliner', 'warplane', 'airship', 'balloon', 'space shuttle', 'fireboat', 'gondola', 'speedboat', 'lifeboat', 'canoe', 'yawl', 'catamaran', 'trimaran', 'container ship', 'liner', 'pirate', 'aircraft carrier', 'submarine', 'wreck', 'half track', 'tank', 'missile', 'bobsled', 'dogsled', 'bicycle-built-for-two', 'mountain bike', 'freight car', 'passenger car', 'barrow', 'shopping cart', 'motor scooter', 'forklift', 'electric locomotive', 'steam locomotive', 'amphibian', 'ambulance', 'beach wagon', 'cab', 'convertible', 'jeep', 'limousine', 'minivan', 'Model T', 'racer', 'sports car', 'go-kart', 'golfcart', 'moped', 'snowplow', 'fire engine', 'garbage truck', 'pickup', 'tow truck', 'trailer truck', 'moving van', 'police van', 'recreational vehicle', 'streetcar', 'snowmobile', 'tractor', 'mobile home', 'tricycle', 'unicycle', 'horse cart', 'jinrikisha', 'oxcart', 'bassinet', 'cradle', 'crib', 'four-poster', 'bookcase', 'china cabinet', 'medicine chest', 'chiffonier', 'table lamp', 'file', 'park bench', 'barber chair', 'throne', 'folding chair', 'rocking chair', 'studio couch', 'toilet seat', 'desk', 'pool table', 'dining table', 'entertainment center', 'wardrobe', 'Granny Smith', 'orange', 'lemon', 'fig', 'pineapple', 'banana', 'jackfruit', 'custard apple', 'pomegranate', 'acorn', 'hip', 'ear', 'rapeseed', 'corn', 'buckeye', 'organ', 'upright', 'chime', 'drum', 'gong', 'maraca', 'marimba', 'steel drum', 'banjo', 'cello', 'violin', 'harp', 'acoustic guitar', 'electric guitar', 'cornet', 'French horn', 'trombone', 'harmonica', 'ocarina', 'panpipe', 'bassoon', 'oboe', 'sax', 'flute', 'daisy', "yellow lady's slipper", 'cliff', 'valley', 'alp', 'volcano', 'promontory', 'sandbar', 'coral reef', 'lakeside', 'seashore', 'geyser', 'hatchet', 'cleaver', 'letter opener', 'plane', 'power drill', 'lawn mower', 'hammer', 'corkscrew', 'can opener', 'plunger', 'screwdriver', 'shovel', 'plow', 'chain saw', 'cock', 'hen', 'ostrich', 'brambling', 'goldfinch', 'house finch', 'junco', 'indigo bunting', 'robin', 'bulbul', 'jay', 'magpie', 'chickadee', 'water ouzel', 'kite', 'bald eagle', 'vulture', 'great grey owl', 'black grouse', 'ptarmigan', 'ruffed grouse', 'prairie chicken', 'peacock', 'quail', 'partridge', 'African grey', 'macaw', 'sulphur-crested cockatoo', 'lorikeet', 'coucal', 'bee eater', 'hornbill', 'hummingbird', 'jacamar', 'toucan', 'drake', 'red-breasted merganser', 'goose', 'black swan', 'white stork', 'black stork', 'spoonbill', 'flamingo', 'American egret', 'little blue heron', 'bittern', 'crane', 'limpkin', 'American coot', 'bustard', 'ruddy turnstone', 'red-backed sandpiper', 'redshank', 'dowitcher', 'oystercatcher', 'European gallinule', 'pelican', 'king penguin', 'albatross', 'great white shark', 'tiger shark', 'hammerhead', 'electric ray', 'stingray', 'barracouta', 'coho', 'tench', 'goldfish', 'eel', 'rock beauty', 'anemone fish', 'lionfish', 'puffer', 'sturgeon', 'gar', 'loggerhead', 'leatherback turtle', 'mud turtle', 'terrapin', 'box turtle', 'banded gecko', 'common iguana', 'American chameleon', 'whiptail', 'agama', 'frilled lizard', 'alligator lizard', 'Gila monster', 'green lizard', 'African chameleon', 'Komodo dragon', 'triceratops', 'African crocodile', 'American alligator', 'thunder snake', 'ringneck snake', 'hognose snake', 'green snake', 'king snake', 'garter snake', 'water snake', 'vine snake', 'night snake', 'boa constrictor', 'rock python', 'Indian cobra', 'green mamba', 'sea snake', 'horned viper', 'diamondback', 'sidewinder', 'European fire salamander', 'common newt', 'eft', 'spotted salamander', 'axolotl', 'bullfrog', 'tree frog', 'tailed frog', 'whistle', 'wing', 'paintbrush', 'hand blower', 'oxygen mask', 'snorkel', 'loudspeaker', 'microphone', 'screen', 'mouse', 'electric fan', 'oil filter', 'strainer', 'space heater', 'stove', 'guillotine', 'barometer', 'rule', 'odometer', 'scale', 'analog clock', 'digital clock', 'wall clock', 'hourglass', 'sundial', 'parking meter', 'stopwatch', 'digital watch', 'stethoscope', 'syringe', 'magnetic compass', 'binoculars', 'projector', 'sunglasses', 'loupe', 'radio telescope', 'bow', 'cannon', 'assault rifle', 'rifle', 'projectile', 'computer keyboard', 'typewriter keyboard', 'crane', 'lighter', 'abacus', 'cash machine', 'slide rule', 'desktop computer', 'hand-held computer', 'notebook', 'web site', 'harvester', 'thresher', 'printer', 'slot', 'vending machine', 'sewing machine', 'joystick', 'switch', 'hook', 'car wheel', 'paddlewheel', 'pinwheel', "potter's wheel", 'gas pump', 'carousel', 'swing', 'reel', 'radiator', 'puck', 'hard disc', 'sunglass', 'pick', 'car mirror', 'solar dish', 'remote control', 'disk brake', 'buckle', 'hair slide', 'knot', 'combination lock', 'padlock', 'nail', 'safety pin', 'screw', 'muzzle', 'seat belt', 'ski', 'candle', "jack-o'-lantern", 'spotlight', 'torch', 'neck brace', 'pier', 'tripod', 'maypole', 'mousetrap', 'spider web', 'trilobite', 'harvestman', 'scorpion', 'black and gold garden spider', 'barn spider', 'garden spider', 'black widow', 'tarantula', 'wolf spider', 'tick', 'centipede', 'isopod', 'Dungeness crab', 'rock crab', 'fiddler crab', 'king crab', 'American lobster', 'spiny lobster', 'crayfish', 'hermit crab', 'tiger beetle', 'ladybug', 'ground beetle', 'long-horned beetle', 'leaf beetle', 'dung beetle', 'rhinoceros beetle', 'weevil', 'fly', 'bee', 'grasshopper', 'cricket', 'walking stick', 'cockroach', 'mantis', 'cicada', 'leafhopper', 'lacewing', 'dragonfly', 'damselfly', 'admiral', 'ringlet', 'monarch', 'cabbage butterfly', 'sulphur butterfly', 'lycaenid', 'jellyfish', 'sea anemone', 'brain coral', 'flatworm', 'nematode', 'conch', 'snail', 'slug', 'sea slug', 'chiton', 'sea urchin', 'sea cucumber', 'iron', 'espresso maker', 'microwave', 'Dutch oven', 'rotisserie', 'toaster', 'waffle iron', 'vacuum', 'dishwasher', 'refrigerator', 'washer', 'Crock Pot', 'frying pan', 'wok', 'caldron', 'coffeepot', 'teapot', 'spatula', 'altar', 'triumphal arch', 'patio', 'steel arch bridge', 'suspension bridge', 'viaduct', 'barn', 'greenhouse', 'palace', 'monastery', 'library', 'apiary', 'boathouse', 'church', 'mosque', 'stupa', 'planetarium', 'restaurant', 'cinema', 'home theater', 'lumbermill', 'coil', 'obelisk', 'totem pole', 'castle', 'prison', 'grocery store', 'bakery', 'barbershop', 'bookshop', 'butcher shop', 'confectionery', 'shoe shop', 'tobacco shop', 'toyshop', 'fountain', 'cliff dwelling', 'yurt', 'dock', 'brass', 'megalith', 'bannister', 'breakwater', 'dam', 'chainlink fence', 'picket fence', 'worm fence', 'stone wall', 'grille', 'sliding door', 'turnstile', 'mountain tent', 'scoreboard', 'honeycomb', 'plate rack', 'pedestal', 'beacon', 'mashed potato', 'bell pepper', 'head cabbage', 'broccoli', 'cauliflower', 'zucchini', 'spaghetti squash', 'acorn squash', 'butternut squash', 'cucumber', 'artichoke', 'cardoon', 'mushroom', 'shower curtain', 'jean', 'carton', 'handkerchief', 'sandal', 'ashcan', 'safe', 'plate', 'necklace', 'croquet ball', 'fur coat', 'thimble', 'pajama', 'running shoe', 'cocktail shaker', 'chest', 'manhole cover', 'modem', 'tub', 'tray', 'balance beam', 'bagel', 'prayer rug', 'kimono', 'hot pot', 'whiskey jug', 'knee pad', 'book jacket', 'spindle', 'ski mask', 'beer bottle', 'crash helmet', 'bottlecap', 'tile roof', 'mask', 'maillot', 'Petri dish', 'football helmet', 'bathing cap', 'teddy', 'holster', 'pop bottle', 'photocopier', 'vestment', 'crossword puzzle', 'golf ball', 'trifle', 'suit', 'water tower', 'feather boa', 'cloak', 'red wine', 'drumstick', 'shield', 'Christmas stocking', 'hoopskirt', 'menu', 'stage', 'bonnet', 'meat loaf', 'baseball', 'face powder', 'scabbard', 'sunscreen', 'beer glass', 'hen-of-the-woods', 'guacamole', 'lampshade', 'wool', 'hay', 'bow tie', 'mailbag', 'water jug', 'bucket', 'dishrag', 'soup bowl', 'eggnog', 'mortar', 'trench coat', 'paddle', 'chain', 'swab', 'mixing bowl', 'potpie', 'wine bottle', 'shoji', 'bulletproof vest', 'drilling platform', 'binder', 'cardigan', 'sweatshirt', 'pot', 'birdhouse', 'hamper', 'ping-pong ball', 'pencil box', 'pay-phone', 'consomme', 'apron', 'punching bag', 'backpack', 'groom', 'bearskin', 'pencil sharpener', 'broom', 'mosquito net', 'abaya', 'mortarboard', 'poncho', 'crutch', 'Polaroid camera', 'space bar', 'cup', 'racket', 'traffic light', 'quill', 'radio', 'dough', 'cuirass', 'military uniform', 'lipstick', 'shower cap', 'monitor', 'oscilloscope', 'mitten', 'brassiere', 'French loaf', 'vase', 'milk can', 'rugby ball', 'paper towel', 'earthstar', 'envelope', 'miniskirt', 'cowboy hat', 'trolleybus', 'perfume', 'bathtub', 'hotdog', 'coral fungus', 'bullet train', 'pillow', 'toilet tissue', 'cassette', "carpenter's kit", 'ladle', 'stinkhorn', 'lotion', 'hair spray', 'academic gown', 'dome', 'crate', 'wig', 'burrito', 'pill bottle', 'chain mail', 'theater curtain', 'window shade', 'barrel', 'washbasin', 'ballpoint', 'basketball', 'bath towel', 'cowboy boot', 'gown', 'window screen', 'agaric', 'cellular telephone', 'nipple', 'barbell', 'mailbox', 'lab coat', 'fire screen', 'minibus', 'packet', 'maze', 'pole', 'horizontal bar', 'sombrero', 'pickelhaube', 'rain barrel', 'wallet', 'cassette player', 'comic book', 'piggy bank', 'street sign', 'bell cote', 'fountain pen', 'Windsor tie', 'volleyball', 'overskirt', 'sarong', 'purse', 'bolo tie', 'bib', 'parachute', 'sleeping bag', 'television', 'swimming trunks', 'measuring cup', 'espresso', 'pizza', 'breastplate', 'shopping basket', 'wooden spoon', 'saltshaker', 'chocolate sauce', 'ballplayer', 'goblet', 'gyromitra', 'stretcher', 'water bottle', 'dial telephone', 'soap dispenser', 'jersey', 'school bus', 'jigsaw puzzle', 'plastic bag', 'reflex camera', 'diaper', 'Band Aid', 'ice lolly', 'velvet', 'tennis ball', 'gasmask', 'doormat', 'Loafer', 'ice cream', 'pretzel', 'quilt', 'maillot', 'tape player', 'clog', 'iPod', 'bolete', 'scuba diver', 'pitcher', 'matchstick', 'bikini', 'sock', 'CD player', 'lens cap', 'thatch', 'vault', 'beaker', 'bubble', 'cheeseburger', 'parallel bars', 'flagpole', 'coffee mug', 'rubber eraser', 'stole', 'carbonara', 'dumbbell'] \ No newline at end of file From 47c775e07135478dbee525e34c50b9b7dd523061 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Thu, 25 Apr 2024 01:33:30 +0000 Subject: [PATCH 66/91] Ruff fix --- src/netspresso_trainer/dataloaders/classification.py | 4 ++-- src/netspresso_trainer/dataloaders/detection.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/netspresso_trainer/dataloaders/classification.py b/src/netspresso_trainer/dataloaders/classification.py index 47021708e..bae6fe5de 100644 --- a/src/netspresso_trainer/dataloaders/classification.py +++ b/src/netspresso_trainer/dataloaders/classification.py @@ -1,14 +1,14 @@ +import os from functools import partial from itertools import chain from multiprocessing.pool import ThreadPool from pathlib import Path from typing import Dict, List, Optional, Tuple, Union -from omegaconf import ListConfig -import os import PIL.Image as Image import torch.distributed as dist from loguru import logger +from omegaconf import ListConfig from .base import BaseCustomDataset, BaseHFDataset, BaseSampleLoader from .utils.constants import IMG_EXTENSIONS diff --git a/src/netspresso_trainer/dataloaders/detection.py b/src/netspresso_trainer/dataloaders/detection.py index 3d4edb37c..f387df320 100644 --- a/src/netspresso_trainer/dataloaders/detection.py +++ b/src/netspresso_trainer/dataloaders/detection.py @@ -1,16 +1,16 @@ +import os from functools import partial from itertools import chain from multiprocessing.pool import ThreadPool from pathlib import Path from typing import Dict, List, Optional, Tuple, Union -from omegaconf import ListConfig -import os import numpy as np import PIL.Image as Image import torch import torch.distributed as dist from loguru import logger +from omegaconf import ListConfig from .base import BaseCustomDataset, BaseSampleLoader from .utils.constants import IMG_EXTENSIONS From 0f87d024decdc544e89db9146e67dec3043aaaf5 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Thu, 25 Apr 2024 01:39:42 +0000 Subject: [PATCH 67/91] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f17729330..f34566ef1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Add dataset validation step and refactoring data modules by `@illian01` in [PR 417](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/417), [PR 419](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/419) - Add various dataset examples including automatic open dataset format converter by `@illian01` in [PR 430](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/430) +- Allow using text file path for the `id_mapping` field (for classification and detection) by `@illian01` in [PR 432](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/432) ## Bug Fixes: From c9be652aabba03084c81082a79099be271fbbe3a Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 30 Apr 2024 08:23:14 +0000 Subject: [PATCH 68/91] Set exist_ok --- tools/open_dataset_tool/voc2012_seg.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/open_dataset_tool/voc2012_seg.py b/tools/open_dataset_tool/voc2012_seg.py index ea82532c2..89211366a 100644 --- a/tools/open_dataset_tool/voc2012_seg.py +++ b/tools/open_dataset_tool/voc2012_seg.py @@ -57,8 +57,8 @@ def unpickle(file): train_image_dir = voc2012_path / 'images' / 'train' train_label_dir = voc2012_path / 'labels' / 'train' - os.makedirs(train_image_dir) - os.makedirs(train_label_dir) + os.makedirs(train_image_dir, exist_ok=True) + os.makedirs(train_label_dir, exist_ok=True) for sample in train_samples: shutil.move(img_src / (sample + '.jpg'), train_image_dir / (sample + '.jpg')) shutil.move(label_src / (sample + '.png'), train_label_dir / (sample + '.png')) @@ -73,8 +73,8 @@ def unpickle(file): valid_image_dir = voc2012_path / 'images' / 'valid' valid_label_dir = voc2012_path / 'labels' / 'valid' - os.makedirs(valid_image_dir) - os.makedirs(valid_label_dir) + os.makedirs(valid_image_dir, exist_ok=True) + os.makedirs(valid_label_dir, exist_ok=True) for sample in valid_samples: shutil.move(img_src / (sample + '.jpg'), valid_image_dir / (sample + '.jpg')) shutil.move(label_src / (sample + '.png'), valid_label_dir / (sample + '.png')) From e03843ec88767f4b946b46a6bc8b2b4a834c92f5 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 30 Apr 2024 08:23:31 +0000 Subject: [PATCH 69/91] Add id_mapping save --- tools/open_dataset_tool/voc2012_seg.py | 33 ++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tools/open_dataset_tool/voc2012_seg.py b/tools/open_dataset_tool/voc2012_seg.py index 89211366a..545d213db 100644 --- a/tools/open_dataset_tool/voc2012_seg.py +++ b/tools/open_dataset_tool/voc2012_seg.py @@ -13,6 +13,30 @@ DEFAULT_DATA_DIR = './data' DOWNLOAD_DIR = './data/download' VOC2012_URL = 'http://host.robots.ox.ac.uk/pascal/VOC/voc2012/VOCtrainval_11-May-2012.tar' +VOC2012_ID_MAPPING_RGB = { + (0, 0, 0): 'background', + (128, 0, 0): 'aeroplane', + (0, 128, 0): 'bicycle', + (128, 128, 0): 'bird', + (0, 0, 128): 'boat', + (128, 0, 128): 'bottle', + (0, 128, 128): 'bus', + (128, 128, 128): 'car', + (64, 0, 0): 'cat', + (192, 0, 0): 'chair', + (64, 128, 0): 'cow', + (192, 128, 0): 'diningtable', + (64, 0, 128): 'dog', + (192, 0, 128): 'horse', + (64, 128, 128): 'motorbike', + (192, 128, 128): 'person', + (0, 64, 0): 'pottedplant', + (128, 64, 0): 'sheep', + (0, 192, 0): 'sofa', + (128, 192, 0): 'train', + (0, 64, 128): 'tvmonitor', + (128, 64, 128): 'void', +} def unpickle(file): @@ -79,6 +103,15 @@ def unpickle(file): shutil.move(img_src / (sample + '.jpg'), valid_image_dir / (sample + '.jpg')) shutil.move(label_src / (sample + '.png'), valid_label_dir / (sample + '.png')) + # Build id_mapping + text = '' + for color, label in VOC2012_ID_MAPPING_RGB.items(): + text += f'{color}:{label}\n' + + with open(voc2012_path / 'rgb_id_mapping.txt', 'w') as f: + f.write(text) + f.close() + try: shutil.rmtree(voc2012_path / 'VOCdevkit') except OSError as e: From fc81ece087e02294f041c948b1dfcb4bc03812fd Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 30 Apr 2024 08:35:51 +0000 Subject: [PATCH 70/91] Change error --- src/netspresso_trainer/dataloaders/classification.py | 2 +- src/netspresso_trainer/dataloaders/detection.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/netspresso_trainer/dataloaders/classification.py b/src/netspresso_trainer/dataloaders/classification.py index bae6fe5de..e542f194e 100644 --- a/src/netspresso_trainer/dataloaders/classification.py +++ b/src/netspresso_trainer/dataloaders/classification.py @@ -55,7 +55,7 @@ def load_id_mapping(self): elif isinstance(self.conf_data.id_mapping, str): id_mapping_path = root_path / self.conf_data.id_mapping if not os.path.isfile(id_mapping_path): - raise ValueError(f"Cannot find file {id_mapping_path}") + FileNotFoundError(f"File not found: {id_mapping_path}") with open(id_mapping_path, 'r') as f: lines = f.readlines() diff --git a/src/netspresso_trainer/dataloaders/detection.py b/src/netspresso_trainer/dataloaders/detection.py index f387df320..4febacdd1 100644 --- a/src/netspresso_trainer/dataloaders/detection.py +++ b/src/netspresso_trainer/dataloaders/detection.py @@ -61,7 +61,7 @@ def load_id_mapping(self): elif isinstance(self.conf_data.id_mapping, str): id_mapping_path = root_path / self.conf_data.id_mapping if not os.path.isfile(id_mapping_path): - raise ValueError(f"Cannot find file {id_mapping_path}") + raise FileNotFoundError(f"File not found: {id_mapping_path}") with open(id_mapping_path, 'r') as f: lines = f.readlines() From f60a1fca1cd2adfcaa4d528b182a68372f1c3beb Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 30 Apr 2024 09:50:36 +0000 Subject: [PATCH 71/91] Add label image mode and change id_mapping to json --- tools/open_dataset_tool/voc2012_seg.py | 91 +++++++++++++++----------- 1 file changed, 53 insertions(+), 38 deletions(-) diff --git a/tools/open_dataset_tool/voc2012_seg.py b/tools/open_dataset_tool/voc2012_seg.py index 545d213db..68cd247ea 100644 --- a/tools/open_dataset_tool/voc2012_seg.py +++ b/tools/open_dataset_tool/voc2012_seg.py @@ -3,39 +3,41 @@ import os import tarfile import shutil +import json import cv2 import numpy as np import pandas as pd import torch from tqdm import tqdm +from PIL import Image DEFAULT_DATA_DIR = './data' DOWNLOAD_DIR = './data/download' VOC2012_URL = 'http://host.robots.ox.ac.uk/pascal/VOC/voc2012/VOCtrainval_11-May-2012.tar' VOC2012_ID_MAPPING_RGB = { - (0, 0, 0): 'background', - (128, 0, 0): 'aeroplane', - (0, 128, 0): 'bicycle', - (128, 128, 0): 'bird', - (0, 0, 128): 'boat', - (128, 0, 128): 'bottle', - (0, 128, 128): 'bus', - (128, 128, 128): 'car', - (64, 0, 0): 'cat', - (192, 0, 0): 'chair', - (64, 128, 0): 'cow', - (192, 128, 0): 'diningtable', - (64, 0, 128): 'dog', - (192, 0, 128): 'horse', - (64, 128, 128): 'motorbike', - (192, 128, 128): 'person', - (0, 64, 0): 'pottedplant', - (128, 64, 0): 'sheep', - (0, 192, 0): 'sofa', - (128, 192, 0): 'train', - (0, 64, 128): 'tvmonitor', - (128, 64, 128): 'void', + '(0, 0, 0)': 'background', + '(128, 0, 0)': 'aeroplane', + '(0, 128, 0)': 'bicycle', + '(128, 128, 0)': 'bird', + '(0, 0, 128)': 'boat', + '(128, 0, 128)': 'bottle', + '(0, 128, 128)': 'bus', + '(128, 128, 128)': 'car', + '(64, 0, 0)': 'cat', + '(192, 0, 0)': 'chair', + '(64, 128, 0)': 'cow', + '(192, 128, 0)': 'diningtable', + '(64, 0, 128)': 'dog', + '(192, 0, 128)': 'horse', + '(64, 128, 128)': 'motorbike', + '(192, 128, 128)': 'person', + '(0, 64, 0)': 'pottedplant', + '(128, 64, 0)': 'sheep', + '(0, 192, 0)': 'sofa', + '(128, 192, 0)': 'train', + '(0, 64, 128)': 'tvmonitor', + '(128, 64, 128)': 'void', } @@ -50,6 +52,7 @@ def unpickle(file): # Set argument (data directory) parser = argparse.ArgumentParser(description="Parser for VOC 2012 dataset downloader.") parser.add_argument('--dir', type=str, default=DEFAULT_DATA_DIR) + parser.add_argument('--label_image_mode', type=str, default='P', choices=['RGB', 'P', 'L'], help='Label image mode (RGB or P or L)') args = parser.parse_args() # Download VOC 2012 dataset @@ -59,10 +62,10 @@ def unpickle(file): print(f'Download path {download_path} already exists! download step is skipped.') else: torch.hub.download_url_to_file(VOC2012_URL, download_path) - + # Extract tar file ap = tarfile.open(download_path) - + voc2012_path = Path(args.dir) / 'voc2012_seg' os.makedirs(voc2012_path, exist_ok=True) ap.extractall(voc2012_path) @@ -80,13 +83,19 @@ def unpickle(file): # Move train images and masks train_image_dir = voc2012_path / 'images' / 'train' train_label_dir = voc2012_path / 'labels' / 'train' - + os.makedirs(train_image_dir, exist_ok=True) os.makedirs(train_label_dir, exist_ok=True) - for sample in train_samples: + for sample in tqdm(train_samples): shutil.move(img_src / (sample + '.jpg'), train_image_dir / (sample + '.jpg')) - shutil.move(label_src / (sample + '.png'), train_label_dir / (sample + '.png')) - + if args.label_image_mode == 'L': + label = Image.open(label_src / (sample + '.png')) + label = np.array(label) + label = Image.fromarray(label, mode='L') + label.save(train_label_dir / (sample + '.png')) + else: + Image.open(label_src / (sample + '.png')).save(train_label_dir / (sample + '.png')) + # Get valid sample list valid_samples = voc2012_path / 'VOCdevkit' / 'VOC2012' / 'ImageSets' / 'Segmentation' / 'val.txt' with open(valid_samples, 'r') as f: @@ -99,18 +108,24 @@ def unpickle(file): os.makedirs(valid_image_dir, exist_ok=True) os.makedirs(valid_label_dir, exist_ok=True) - for sample in valid_samples: + for sample in tqdm(valid_samples): shutil.move(img_src / (sample + '.jpg'), valid_image_dir / (sample + '.jpg')) - shutil.move(label_src / (sample + '.png'), valid_label_dir / (sample + '.png')) - + if args.label_image_mode == 'L': + label = Image.open(label_src / (sample + '.png')) + label = np.array(label) + label = Image.fromarray(label, mode='L') + label.save(valid_label_dir / (sample + '.png')) + else: + Image.open(label_src / (sample + '.png')).save(valid_label_dir / (sample + '.png')) + # Build id_mapping - text = '' - for color, label in VOC2012_ID_MAPPING_RGB.items(): - text += f'{color}:{label}\n' - - with open(voc2012_path / 'rgb_id_mapping.txt', 'w') as f: - f.write(text) - f.close() + if args.label_image_mode == 'L': + id_mapping_to_save = list(VOC2012_ID_MAPPING_RGB.values()) + else: + id_mapping_to_save = VOC2012_ID_MAPPING_RGB + + with open(voc2012_path / 'id_mapping.json', 'w') as f: + json.dump(id_mapping_to_save, f) try: shutil.rmtree(voc2012_path / 'VOCdevkit') From 85265360aba27fec377d78a39ed351dfd119f3e2 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 30 Apr 2024 09:50:50 +0000 Subject: [PATCH 72/91] Update voc2012 configs --- config/data/local/voc12.yaml | 46 +++++++++---------- .../data/local/voc12_grayscale_converted.yaml | 25 +--------- 2 files changed, 25 insertions(+), 46 deletions(-) diff --git a/config/data/local/voc12.yaml b/config/data/local/voc12.yaml index 24952a5db..e0a55d564 100644 --- a/config/data/local/voc12.yaml +++ b/config/data/local/voc12.yaml @@ -17,27 +17,27 @@ data: image: ~ label: ~ label_image_mode: RGB - id_mapping: - (0, 0, 0): background - (128, 0, 0): aeroplane - (0, 128, 0): bicycle - (128, 128, 0): bird - (0, 0, 128): boat - (128, 0, 128): bottle - (0, 128, 128): bus - (128, 128, 128): car - (64, 0, 0): cat - (192, 0, 0): chair - (64, 128, 0): cow - (192, 128, 0): diningtable - (64, 0, 128): dog - (192, 0, 128): horse - (64, 128, 128): motorbike - (192, 128, 128): person - (0, 64, 0): pottedplant - (128, 64, 0): sheep - (0, 192, 0): sofa - (128, 192, 0): train - (0, 64, 128): tvmonitor - (128, 64, 128): void + id_mapping: id_mapping.json + # (0, 0, 0): background + # (128, 0, 0): aeroplane + # (0, 128, 0): bicycle + # (128, 128, 0): bird + # (0, 0, 128): boat + # (128, 0, 128): bottle + # (0, 128, 128): bus + # (128, 128, 128): car + # (64, 0, 0): cat + # (192, 0, 0): chair + # (64, 128, 0): cow + # (192, 128, 0): diningtable + # (64, 0, 128): dog + # (192, 0, 128): horse + # (64, 128, 128): motorbike + # (192, 128, 128): person + # (0, 64, 0): pottedplant + # (128, 64, 0): sheep + # (0, 192, 0): sofa + # (128, 192, 0): train + # (0, 64, 128): tvmonitor + # (128, 64, 128): void pallete: ~ \ No newline at end of file diff --git a/config/data/local/voc12_grayscale_converted.yaml b/config/data/local/voc12_grayscale_converted.yaml index 29be8d0a8..332268efc 100644 --- a/config/data/local/voc12_grayscale_converted.yaml +++ b/config/data/local/voc12_grayscale_converted.yaml @@ -17,26 +17,5 @@ data: image: ~ label: ~ label_image_mode: L - id_mapping: ['background', 'aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor'] - pallete: - - [0, 0, 0] - - [128, 0, 0] - - [0, 128, 0] - - [128, 128, 0] - - [0, 0, 128] - - [128, 0, 128] - - [0, 128, 128] - - [128, 128, 128] - - [64, 0, 0] - - [192, 0, 0] - - [64, 128, 0] - - [192, 128, 0] - - [64, 0, 128] - - [192, 0, 128] - - [64, 128, 128] - - [192, 128, 128] - - [0, 64, 0] - - [128, 64, 0] - - [0, 192, 0] - - [128, 192, 0] - - [0, 64, 128] \ No newline at end of file + id_mapping: id_mapping.json + #id_mapping: ['background', 'aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor'] \ No newline at end of file From d58633208659ec40b59bce7d96dd4dfe5a4a0639 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 30 Apr 2024 09:51:10 +0000 Subject: [PATCH 73/91] Fix segmentation load_id_mapping --- .../dataloaders/segmentation.py | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/netspresso_trainer/dataloaders/segmentation.py b/src/netspresso_trainer/dataloaders/segmentation.py index 15c990b27..29d4ada79 100644 --- a/src/netspresso_trainer/dataloaders/segmentation.py +++ b/src/netspresso_trainer/dataloaders/segmentation.py @@ -1,8 +1,10 @@ +import os from functools import partial from itertools import chain from multiprocessing.pool import ThreadPool from pathlib import Path from typing import Dict, List, Literal, Optional, Tuple, Union +import json import numpy as np import PIL.Image as Image @@ -49,15 +51,27 @@ def load_data(self, split='train'): return images_and_targets def load_id_mapping(self): - return self.conf_data.id_mapping + root_path = Path(self.conf_data.path.root) + + if isinstance(self.conf_data.id_mapping, DictConfig): + return dict(self.conf_data.id_mapping) + elif isinstance(self.conf_data.id_mapping, ListConfig): + return dict(enumerate(self.conf_data.id_mapping)) + elif isinstance(self.conf_data.id_mapping, str): + id_mapping_path = root_path / self.conf_data.id_mapping + if not os.path.exists(id_mapping_path): + raise FileNotFoundError(f"File not found: {id_mapping_path}") + + with open(id_mapping_path, 'r') as f: + id_mapping = json.load(f) + if isinstance(id_mapping, list): + id_mapping = dict(enumerate(id_mapping)) + + return id_mapping + else: + raise ValueError(f"Unknown type for id_mapping! {type(self.conf_data.id_mapping)}") def load_class_map(self, id_mapping): - if isinstance(id_mapping, ListConfig): - assert isinstance(id_mapping[0], str), f"Unknown type for class name! {type(id_mapping[0])}" - idx_to_class: Dict[int, str] = dict(enumerate(id_mapping)) - label_value_to_idx = {k: k for k in idx_to_class} - return {'idx_to_class': idx_to_class, 'label_value_to_idx': label_value_to_idx} - idx_to_class: Dict[int, str] = {} label_value_to_idx: Dict[Union[int, Tuple], int] = {} for class_idx, (label_value, class_name) in enumerate(id_mapping.items()): From e0e8d96ef6508a4d46eef931cda5069920556a15 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Tue, 30 Apr 2024 10:08:58 +0000 Subject: [PATCH 74/91] Change id_mapping to json --- config/data/local/cifar100.yaml | 2 +- config/data/local/coco2017.yaml | 2 +- config/data/local/imagenet1k.yaml | 3 +-- src/netspresso_trainer/dataloaders/classification.py | 5 +++-- src/netspresso_trainer/dataloaders/detection.py | 5 +++-- tools/open_dataset_tool/cifar100.py | 7 +++---- tools/open_dataset_tool/coco2017.py | 5 ++--- tools/open_dataset_tool/imagenet1k.py | 7 ++++--- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/config/data/local/cifar100.yaml b/config/data/local/cifar100.yaml index c1b53bda1..d73d80f03 100644 --- a/config/data/local/cifar100.yaml +++ b/config/data/local/cifar100.yaml @@ -13,5 +13,5 @@ data: test: image: ~ label: ~ - id_mapping: id_mapping.txt + id_mapping: id_mapping.json # id_mapping: ['apple', 'aquarium_fish', 'baby', 'bear', 'beaver', 'bed', 'bee', 'beetle', 'bicycle', 'bottle', 'bowl', 'boy', 'bridge', 'bus', 'butterfly', 'camel', 'can', 'castle', 'caterpillar', 'cattle', 'chair', 'chimpanzee', 'clock', 'cloud', 'cockroach', 'couch', 'crab', 'crocodile', 'cup', 'dinosaur', 'dolphin', 'elephant', 'flatfish', 'forest', 'fox', 'girl', 'hamster', 'house', 'kangaroo', 'keyboard', 'lamp', 'lawn_mower', 'leopard', 'lion', 'lizard', 'lobster', 'man', 'maple_tree', 'motorcycle', 'mountain', 'mouse', 'mushroom', 'oak_tree', 'orange', 'orchid', 'otter', 'palm_tree', 'pear', 'pickup_truck', 'pine_tree', 'plain', 'plate', 'poppy', 'porcupine', 'possum', 'rabbit', 'raccoon', 'ray', 'road', 'rocket', 'rose', 'sea', 'seal', 'shark', 'shrew', 'skunk', 'skyscraper', 'snail', 'snake', 'spider', 'squirrel', 'streetcar', 'sunflower', 'sweet_pepper', 'table', 'tank', 'telephone', 'television', 'tiger', 'tractor', 'train', 'trout', 'tulip', 'turtle', 'wardrobe', 'whale', 'willow_tree', 'wolf', 'woman', 'worm'] \ No newline at end of file diff --git a/config/data/local/coco2017.yaml b/config/data/local/coco2017.yaml index 56143ede4..86801f45a 100644 --- a/config/data/local/coco2017.yaml +++ b/config/data/local/coco2017.yaml @@ -16,6 +16,6 @@ data: pattern: image: ~ label: ~ - id_mapping: id_mapping.txt + id_mapping: id_mapping.json # id_mapping: ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] pallete: ~ diff --git a/config/data/local/imagenet1k.yaml b/config/data/local/imagenet1k.yaml index 62e419fda..4364862ed 100644 --- a/config/data/local/imagenet1k.yaml +++ b/config/data/local/imagenet1k.yaml @@ -13,5 +13,4 @@ data: test: image: ~ label: ~ - id_mapping: id_mapping.txt - #id_mapping: ['kit fox', 'English setter', 'Siberian husky', 'Australian terrier', 'English springer', 'grey whale', 'lesser panda', 'Egyptian cat', 'ibex', 'Persian cat', 'cougar', 'gazelle', 'porcupine', 'sea lion', 'malamute', 'badger', 'Great Dane', 'Walker hound', 'Welsh springer spaniel', 'whippet', 'Scottish deerhound', 'killer whale', 'mink', 'African elephant', 'Weimaraner', 'soft-coated wheaten terrier', 'Dandie Dinmont', 'red wolf', 'Old English sheepdog', 'jaguar', 'otterhound', 'bloodhound', 'Airedale', 'hyena', 'meerkat', 'giant schnauzer', 'titi', 'three-toed sloth', 'sorrel', 'black-footed ferret', 'dalmatian', 'black-and-tan coonhound', 'papillon', 'skunk', 'Staffordshire bullterrier', 'Mexican hairless', 'Bouvier des Flandres', 'weasel', 'miniature poodle', 'Cardigan', 'malinois', 'bighorn', 'fox squirrel', 'colobus', 'tiger cat', 'Lhasa', 'impala', 'coyote', 'Yorkshire terrier', 'Newfoundland', 'brown bear', 'red fox', 'Norwegian elkhound', 'Rottweiler', 'hartebeest', 'Saluki', 'grey fox', 'schipperke', 'Pekinese', 'Brabancon griffon', 'West Highland white terrier', 'Sealyham terrier', 'guenon', 'mongoose', 'indri', 'tiger', 'Irish wolfhound', 'wild boar', 'EntleBucher', 'zebra', 'ram', 'French bulldog', 'orangutan', 'basenji', 'leopard', 'Bernese mountain dog', 'Maltese dog', 'Norfolk terrier', 'toy terrier', 'vizsla', 'cairn', 'squirrel monkey', 'groenendael', 'clumber', 'Siamese cat', 'chimpanzee', 'komondor', 'Afghan hound', 'Japanese spaniel', 'proboscis monkey', 'guinea pig', 'white wolf', 'ice bear', 'gorilla', 'borzoi', 'toy poodle', 'Kerry blue terrier', 'ox', 'Scotch terrier', 'Tibetan mastiff', 'spider monkey', 'Doberman', 'Boston bull', 'Greater Swiss Mountain dog', 'Appenzeller', 'Shih-Tzu', 'Irish water spaniel', 'Pomeranian', 'Bedlington terrier', 'warthog', 'Arabian camel', 'siamang', 'miniature schnauzer', 'collie', 'golden retriever', 'Irish terrier', 'affenpinscher', 'Border collie', 'hare', 'boxer', 'silky terrier', 'beagle', 'Leonberg', 'German short-haired pointer', 'patas', 'dhole', 'baboon', 'macaque', 'Chesapeake Bay retriever', 'bull mastiff', 'kuvasz', 'capuchin', 'pug', 'curly-coated retriever', 'Norwich terrier', 'flat-coated retriever', 'hog', 'keeshond', 'Eskimo dog', 'Brittany spaniel', 'standard poodle', 'Lakeland terrier', 'snow leopard', 'Gordon setter', 'dingo', 'standard schnauzer', 'hamster', 'Tibetan terrier', 'Arctic fox', 'wire-haired fox terrier', 'basset', 'water buffalo', 'American black bear', 'Angora', 'bison', 'howler monkey', 'hippopotamus', 'chow', 'giant panda', 'American Staffordshire terrier', 'Shetland sheepdog', 'Great Pyrenees', 'Chihuahua', 'tabby', 'marmoset', 'Labrador retriever', 'Saint Bernard', 'armadillo', 'Samoyed', 'bluetick', 'redbone', 'polecat', 'marmot', 'kelpie', 'gibbon', 'llama', 'miniature pinscher', 'wood rabbit', 'Italian greyhound', 'lion', 'cocker spaniel', 'Irish setter', 'dugong', 'Indian elephant', 'beaver', 'Sussex spaniel', 'Pembroke', 'Blenheim spaniel', 'Madagascar cat', 'Rhodesian ridgeback', 'lynx', 'African hunting dog', 'langur', 'Ibizan hound', 'timber wolf', 'cheetah', 'English foxhound', 'briard', 'sloth bear', 'Border terrier', 'German shepherd', 'otter', 'koala', 'tusker', 'echidna', 'wallaby', 'platypus', 'wombat', 'revolver', 'umbrella', 'schooner', 'soccer ball', 'accordion', 'ant', 'starfish', 'chambered nautilus', 'grand piano', 'laptop', 'strawberry', 'airliner', 'warplane', 'airship', 'balloon', 'space shuttle', 'fireboat', 'gondola', 'speedboat', 'lifeboat', 'canoe', 'yawl', 'catamaran', 'trimaran', 'container ship', 'liner', 'pirate', 'aircraft carrier', 'submarine', 'wreck', 'half track', 'tank', 'missile', 'bobsled', 'dogsled', 'bicycle-built-for-two', 'mountain bike', 'freight car', 'passenger car', 'barrow', 'shopping cart', 'motor scooter', 'forklift', 'electric locomotive', 'steam locomotive', 'amphibian', 'ambulance', 'beach wagon', 'cab', 'convertible', 'jeep', 'limousine', 'minivan', 'Model T', 'racer', 'sports car', 'go-kart', 'golfcart', 'moped', 'snowplow', 'fire engine', 'garbage truck', 'pickup', 'tow truck', 'trailer truck', 'moving van', 'police van', 'recreational vehicle', 'streetcar', 'snowmobile', 'tractor', 'mobile home', 'tricycle', 'unicycle', 'horse cart', 'jinrikisha', 'oxcart', 'bassinet', 'cradle', 'crib', 'four-poster', 'bookcase', 'china cabinet', 'medicine chest', 'chiffonier', 'table lamp', 'file', 'park bench', 'barber chair', 'throne', 'folding chair', 'rocking chair', 'studio couch', 'toilet seat', 'desk', 'pool table', 'dining table', 'entertainment center', 'wardrobe', 'Granny Smith', 'orange', 'lemon', 'fig', 'pineapple', 'banana', 'jackfruit', 'custard apple', 'pomegranate', 'acorn', 'hip', 'ear', 'rapeseed', 'corn', 'buckeye', 'organ', 'upright', 'chime', 'drum', 'gong', 'maraca', 'marimba', 'steel drum', 'banjo', 'cello', 'violin', 'harp', 'acoustic guitar', 'electric guitar', 'cornet', 'French horn', 'trombone', 'harmonica', 'ocarina', 'panpipe', 'bassoon', 'oboe', 'sax', 'flute', 'daisy', "yellow lady's slipper", 'cliff', 'valley', 'alp', 'volcano', 'promontory', 'sandbar', 'coral reef', 'lakeside', 'seashore', 'geyser', 'hatchet', 'cleaver', 'letter opener', 'plane', 'power drill', 'lawn mower', 'hammer', 'corkscrew', 'can opener', 'plunger', 'screwdriver', 'shovel', 'plow', 'chain saw', 'cock', 'hen', 'ostrich', 'brambling', 'goldfinch', 'house finch', 'junco', 'indigo bunting', 'robin', 'bulbul', 'jay', 'magpie', 'chickadee', 'water ouzel', 'kite', 'bald eagle', 'vulture', 'great grey owl', 'black grouse', 'ptarmigan', 'ruffed grouse', 'prairie chicken', 'peacock', 'quail', 'partridge', 'African grey', 'macaw', 'sulphur-crested cockatoo', 'lorikeet', 'coucal', 'bee eater', 'hornbill', 'hummingbird', 'jacamar', 'toucan', 'drake', 'red-breasted merganser', 'goose', 'black swan', 'white stork', 'black stork', 'spoonbill', 'flamingo', 'American egret', 'little blue heron', 'bittern', 'crane', 'limpkin', 'American coot', 'bustard', 'ruddy turnstone', 'red-backed sandpiper', 'redshank', 'dowitcher', 'oystercatcher', 'European gallinule', 'pelican', 'king penguin', 'albatross', 'great white shark', 'tiger shark', 'hammerhead', 'electric ray', 'stingray', 'barracouta', 'coho', 'tench', 'goldfish', 'eel', 'rock beauty', 'anemone fish', 'lionfish', 'puffer', 'sturgeon', 'gar', 'loggerhead', 'leatherback turtle', 'mud turtle', 'terrapin', 'box turtle', 'banded gecko', 'common iguana', 'American chameleon', 'whiptail', 'agama', 'frilled lizard', 'alligator lizard', 'Gila monster', 'green lizard', 'African chameleon', 'Komodo dragon', 'triceratops', 'African crocodile', 'American alligator', 'thunder snake', 'ringneck snake', 'hognose snake', 'green snake', 'king snake', 'garter snake', 'water snake', 'vine snake', 'night snake', 'boa constrictor', 'rock python', 'Indian cobra', 'green mamba', 'sea snake', 'horned viper', 'diamondback', 'sidewinder', 'European fire salamander', 'common newt', 'eft', 'spotted salamander', 'axolotl', 'bullfrog', 'tree frog', 'tailed frog', 'whistle', 'wing', 'paintbrush', 'hand blower', 'oxygen mask', 'snorkel', 'loudspeaker', 'microphone', 'screen', 'mouse', 'electric fan', 'oil filter', 'strainer', 'space heater', 'stove', 'guillotine', 'barometer', 'rule', 'odometer', 'scale', 'analog clock', 'digital clock', 'wall clock', 'hourglass', 'sundial', 'parking meter', 'stopwatch', 'digital watch', 'stethoscope', 'syringe', 'magnetic compass', 'binoculars', 'projector', 'sunglasses', 'loupe', 'radio telescope', 'bow', 'cannon', 'assault rifle', 'rifle', 'projectile', 'computer keyboard', 'typewriter keyboard', 'crane', 'lighter', 'abacus', 'cash machine', 'slide rule', 'desktop computer', 'hand-held computer', 'notebook', 'web site', 'harvester', 'thresher', 'printer', 'slot', 'vending machine', 'sewing machine', 'joystick', 'switch', 'hook', 'car wheel', 'paddlewheel', 'pinwheel', "potter's wheel", 'gas pump', 'carousel', 'swing', 'reel', 'radiator', 'puck', 'hard disc', 'sunglass', 'pick', 'car mirror', 'solar dish', 'remote control', 'disk brake', 'buckle', 'hair slide', 'knot', 'combination lock', 'padlock', 'nail', 'safety pin', 'screw', 'muzzle', 'seat belt', 'ski', 'candle', "jack-o'-lantern", 'spotlight', 'torch', 'neck brace', 'pier', 'tripod', 'maypole', 'mousetrap', 'spider web', 'trilobite', 'harvestman', 'scorpion', 'black and gold garden spider', 'barn spider', 'garden spider', 'black widow', 'tarantula', 'wolf spider', 'tick', 'centipede', 'isopod', 'Dungeness crab', 'rock crab', 'fiddler crab', 'king crab', 'American lobster', 'spiny lobster', 'crayfish', 'hermit crab', 'tiger beetle', 'ladybug', 'ground beetle', 'long-horned beetle', 'leaf beetle', 'dung beetle', 'rhinoceros beetle', 'weevil', 'fly', 'bee', 'grasshopper', 'cricket', 'walking stick', 'cockroach', 'mantis', 'cicada', 'leafhopper', 'lacewing', 'dragonfly', 'damselfly', 'admiral', 'ringlet', 'monarch', 'cabbage butterfly', 'sulphur butterfly', 'lycaenid', 'jellyfish', 'sea anemone', 'brain coral', 'flatworm', 'nematode', 'conch', 'snail', 'slug', 'sea slug', 'chiton', 'sea urchin', 'sea cucumber', 'iron', 'espresso maker', 'microwave', 'Dutch oven', 'rotisserie', 'toaster', 'waffle iron', 'vacuum', 'dishwasher', 'refrigerator', 'washer', 'Crock Pot', 'frying pan', 'wok', 'caldron', 'coffeepot', 'teapot', 'spatula', 'altar', 'triumphal arch', 'patio', 'steel arch bridge', 'suspension bridge', 'viaduct', 'barn', 'greenhouse', 'palace', 'monastery', 'library', 'apiary', 'boathouse', 'church', 'mosque', 'stupa', 'planetarium', 'restaurant', 'cinema', 'home theater', 'lumbermill', 'coil', 'obelisk', 'totem pole', 'castle', 'prison', 'grocery store', 'bakery', 'barbershop', 'bookshop', 'butcher shop', 'confectionery', 'shoe shop', 'tobacco shop', 'toyshop', 'fountain', 'cliff dwelling', 'yurt', 'dock', 'brass', 'megalith', 'bannister', 'breakwater', 'dam', 'chainlink fence', 'picket fence', 'worm fence', 'stone wall', 'grille', 'sliding door', 'turnstile', 'mountain tent', 'scoreboard', 'honeycomb', 'plate rack', 'pedestal', 'beacon', 'mashed potato', 'bell pepper', 'head cabbage', 'broccoli', 'cauliflower', 'zucchini', 'spaghetti squash', 'acorn squash', 'butternut squash', 'cucumber', 'artichoke', 'cardoon', 'mushroom', 'shower curtain', 'jean', 'carton', 'handkerchief', 'sandal', 'ashcan', 'safe', 'plate', 'necklace', 'croquet ball', 'fur coat', 'thimble', 'pajama', 'running shoe', 'cocktail shaker', 'chest', 'manhole cover', 'modem', 'tub', 'tray', 'balance beam', 'bagel', 'prayer rug', 'kimono', 'hot pot', 'whiskey jug', 'knee pad', 'book jacket', 'spindle', 'ski mask', 'beer bottle', 'crash helmet', 'bottlecap', 'tile roof', 'mask', 'maillot', 'Petri dish', 'football helmet', 'bathing cap', 'teddy', 'holster', 'pop bottle', 'photocopier', 'vestment', 'crossword puzzle', 'golf ball', 'trifle', 'suit', 'water tower', 'feather boa', 'cloak', 'red wine', 'drumstick', 'shield', 'Christmas stocking', 'hoopskirt', 'menu', 'stage', 'bonnet', 'meat loaf', 'baseball', 'face powder', 'scabbard', 'sunscreen', 'beer glass', 'hen-of-the-woods', 'guacamole', 'lampshade', 'wool', 'hay', 'bow tie', 'mailbag', 'water jug', 'bucket', 'dishrag', 'soup bowl', 'eggnog', 'mortar', 'trench coat', 'paddle', 'chain', 'swab', 'mixing bowl', 'potpie', 'wine bottle', 'shoji', 'bulletproof vest', 'drilling platform', 'binder', 'cardigan', 'sweatshirt', 'pot', 'birdhouse', 'hamper', 'ping-pong ball', 'pencil box', 'pay-phone', 'consomme', 'apron', 'punching bag', 'backpack', 'groom', 'bearskin', 'pencil sharpener', 'broom', 'mosquito net', 'abaya', 'mortarboard', 'poncho', 'crutch', 'Polaroid camera', 'space bar', 'cup', 'racket', 'traffic light', 'quill', 'radio', 'dough', 'cuirass', 'military uniform', 'lipstick', 'shower cap', 'monitor', 'oscilloscope', 'mitten', 'brassiere', 'French loaf', 'vase', 'milk can', 'rugby ball', 'paper towel', 'earthstar', 'envelope', 'miniskirt', 'cowboy hat', 'trolleybus', 'perfume', 'bathtub', 'hotdog', 'coral fungus', 'bullet train', 'pillow', 'toilet tissue', 'cassette', "carpenter's kit", 'ladle', 'stinkhorn', 'lotion', 'hair spray', 'academic gown', 'dome', 'crate', 'wig', 'burrito', 'pill bottle', 'chain mail', 'theater curtain', 'window shade', 'barrel', 'washbasin', 'ballpoint', 'basketball', 'bath towel', 'cowboy boot', 'gown', 'window screen', 'agaric', 'cellular telephone', 'nipple', 'barbell', 'mailbox', 'lab coat', 'fire screen', 'minibus', 'packet', 'maze', 'pole', 'horizontal bar', 'sombrero', 'pickelhaube', 'rain barrel', 'wallet', 'cassette player', 'comic book', 'piggy bank', 'street sign', 'bell cote', 'fountain pen', 'Windsor tie', 'volleyball', 'overskirt', 'sarong', 'purse', 'bolo tie', 'bib', 'parachute', 'sleeping bag', 'television', 'swimming trunks', 'measuring cup', 'espresso', 'pizza', 'breastplate', 'shopping basket', 'wooden spoon', 'saltshaker', 'chocolate sauce', 'ballplayer', 'goblet', 'gyromitra', 'stretcher', 'water bottle', 'dial telephone', 'soap dispenser', 'jersey', 'school bus', 'jigsaw puzzle', 'plastic bag', 'reflex camera', 'diaper', 'Band Aid', 'ice lolly', 'velvet', 'tennis ball', 'gasmask', 'doormat', 'Loafer', 'ice cream', 'pretzel', 'quilt', 'maillot', 'tape player', 'clog', 'iPod', 'bolete', 'scuba diver', 'pitcher', 'matchstick', 'bikini', 'sock', 'CD player', 'lens cap', 'thatch', 'vault', 'beaker', 'bubble', 'cheeseburger', 'parallel bars', 'flagpole', 'coffee mug', 'rubber eraser', 'stole', 'carbonara', 'dumbbell'] \ No newline at end of file + id_mapping: id_mapping.json \ No newline at end of file diff --git a/src/netspresso_trainer/dataloaders/classification.py b/src/netspresso_trainer/dataloaders/classification.py index e542f194e..cad255ea8 100644 --- a/src/netspresso_trainer/dataloaders/classification.py +++ b/src/netspresso_trainer/dataloaders/classification.py @@ -4,6 +4,7 @@ from multiprocessing.pool import ThreadPool from pathlib import Path from typing import Dict, List, Optional, Tuple, Union +import json import PIL.Image as Image import torch.distributed as dist @@ -58,8 +59,8 @@ def load_id_mapping(self): FileNotFoundError(f"File not found: {id_mapping_path}") with open(id_mapping_path, 'r') as f: - lines = f.readlines() - return [line.strip() for line in lines] + id_mapping = json.load(f) + return id_mapping else: raise ValueError(f"Unsupported id_mapping value {self.conf_data.id_mapping}") diff --git a/src/netspresso_trainer/dataloaders/detection.py b/src/netspresso_trainer/dataloaders/detection.py index 4febacdd1..e815bef34 100644 --- a/src/netspresso_trainer/dataloaders/detection.py +++ b/src/netspresso_trainer/dataloaders/detection.py @@ -4,6 +4,7 @@ from multiprocessing.pool import ThreadPool from pathlib import Path from typing import Dict, List, Optional, Tuple, Union +import json import numpy as np import PIL.Image as Image @@ -64,8 +65,8 @@ def load_id_mapping(self): raise FileNotFoundError(f"File not found: {id_mapping_path}") with open(id_mapping_path, 'r') as f: - lines = f.readlines() - return [line.strip() for line in lines] + id_mapping = json.load(f) + return id_mapping else: raise ValueError(f"Unsupported id_mapping value {self.conf_data.id_mapping}") diff --git a/tools/open_dataset_tool/cifar100.py b/tools/open_dataset_tool/cifar100.py index 1bb17ab6b..072870ca9 100644 --- a/tools/open_dataset_tool/cifar100.py +++ b/tools/open_dataset_tool/cifar100.py @@ -3,6 +3,7 @@ import os import tarfile import shutil +import json import cv2 import numpy as np @@ -97,10 +98,8 @@ def unpickle(file): val_label_csv.to_csv(valid_label_dir / 'cifar100_val.csv', mode='w', index=False) # Build id_mapping - id_mapping = CIFAR100_CLASSES - with open(data_dir / 'id_mapping.txt', 'w') as f: - f.write('\n'.join(id_mapping)) - f.close() + with open(data_dir / 'id_mapping.json', 'w') as f: + json.dump(CIFAR100_CLASSES, f) try: shutil.rmtree(extracted_dir) diff --git a/tools/open_dataset_tool/coco2017.py b/tools/open_dataset_tool/coco2017.py index 70adf2b32..4f810c342 100644 --- a/tools/open_dataset_tool/coco2017.py +++ b/tools/open_dataset_tool/coco2017.py @@ -174,9 +174,8 @@ def cxcywh2cxcywhn(cx, cy, w, h, img_w, img_h): # Build id_mapping id_mapping = [CLASS80_LABEL_TO_NAME[i] for i in range(80)] - with open(coco2017_path / 'id_mapping.txt', 'w') as f: - f.write('\n'.join(id_mapping)) - f.close() + with open(coco2017_path / 'id_mapping.json', 'w') as f: + json.dump(id_mapping, f) try: shutil.rmtree(coco2017_path / 'annotations') diff --git a/tools/open_dataset_tool/imagenet1k.py b/tools/open_dataset_tool/imagenet1k.py index 72480d270..51e683faa 100644 --- a/tools/open_dataset_tool/imagenet1k.py +++ b/tools/open_dataset_tool/imagenet1k.py @@ -3,6 +3,7 @@ import os import tarfile import shutil +import json import scipy import cv2 @@ -129,7 +130,7 @@ # Build id_mapping print('Building id_mapping ...') id_mapping = [cls_to_name[i] for i in range(1000)] - with open(imagenet_path / 'id_mapping.txt', 'w') as f: - f.write('\n'.join(id_mapping)) - f.close() + with open(imagenet_path / 'id_mapping.json', 'w') as f: + json.dump(id_mapping, f) + print('Done!') From 6e0c136b23de5919dbe329b9cd894be273408d9c Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Thu, 2 May 2024 05:14:15 +0000 Subject: [PATCH 75/91] Add wflw dataset tool --- tools/open_dataset_tool/wflw.py | 272 ++++++++++++++++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 tools/open_dataset_tool/wflw.py diff --git a/tools/open_dataset_tool/wflw.py b/tools/open_dataset_tool/wflw.py new file mode 100644 index 000000000..555f8ce44 --- /dev/null +++ b/tools/open_dataset_tool/wflw.py @@ -0,0 +1,272 @@ +import argparse +from pathlib import Path +import os +import tarfile +import shutil +import json + +import cv2 +import numpy as np +import pandas as pd +import torch +from tqdm import tqdm + +DEFAULT_DATA_DIR = './data' +DOWNLOAD_DIR = './data/download' +WFLW_IMAGES_URL = 'https://drive.usercontent.google.com/download?id=1hzBd48JIdWTJSsATBEB_eFVvPL1bx6UC&export=download&authuser=1&confirm=t&uuid=a62cb82a-66a0-498c-b568-5b1955f3926d&at=APZUnTX3W3OXP2Y2kHd4OpGltbjL%3A1714472372882' +WFLW_ANNOTATIONS_URL = 'https://wywu.github.io/projects/LAB/support/WFLW_annotations.tar.gz' +KEYPOINT_INFO = { + 0: dict(name='kpt-0', id=0, color=[255, 0, 0], type='', swap='kpt-32'), + 1: dict(name='kpt-1', id=1, color=[255, 0, 0], type='', swap='kpt-31'), + 2: dict(name='kpt-2', id=2, color=[255, 0, 0], type='', swap='kpt-30'), + 3: dict(name='kpt-3', id=3, color=[255, 0, 0], type='', swap='kpt-29'), + 4: dict(name='kpt-4', id=4, color=[255, 0, 0], type='', swap='kpt-28'), + 5: dict(name='kpt-5', id=5, color=[255, 0, 0], type='', swap='kpt-27'), + 6: dict(name='kpt-6', id=6, color=[255, 0, 0], type='', swap='kpt-26'), + 7: dict(name='kpt-7', id=7, color=[255, 0, 0], type='', swap='kpt-25'), + 8: dict(name='kpt-8', id=8, color=[255, 0, 0], type='', swap='kpt-24'), + 9: dict(name='kpt-9', id=9, color=[255, 0, 0], type='', swap='kpt-23'), + 10: dict(name='kpt-10', id=10, color=[255, 0, 0], type='', swap='kpt-22'), + 11: dict(name='kpt-11', id=11, color=[255, 0, 0], type='', swap='kpt-21'), + 12: dict(name='kpt-12', id=12, color=[255, 0, 0], type='', swap='kpt-20'), + 13: dict(name='kpt-13', id=13, color=[255, 0, 0], type='', swap='kpt-19'), + 14: dict(name='kpt-14', id=14, color=[255, 0, 0], type='', swap='kpt-18'), + 15: dict(name='kpt-15', id=15, color=[255, 0, 0], type='', swap='kpt-17'), + 16: dict(name='kpt-16', id=16, color=[255, 0, 0], type='', swap=''), + 17: dict(name='kpt-17', id=17, color=[255, 0, 0], type='', swap='kpt-15'), + 18: dict(name='kpt-18', id=18, color=[255, 0, 0], type='', swap='kpt-14'), + 19: dict(name='kpt-19', id=19, color=[255, 0, 0], type='', swap='kpt-13'), + 20: dict(name='kpt-20', id=20, color=[255, 0, 0], type='', swap='kpt-12'), + 21: dict(name='kpt-21', id=21, color=[255, 0, 0], type='', swap='kpt-11'), + 22: dict(name='kpt-22', id=22, color=[255, 0, 0], type='', swap='kpt-10'), + 23: dict(name='kpt-23', id=23, color=[255, 0, 0], type='', swap='kpt-9'), + 24: dict(name='kpt-24', id=24, color=[255, 0, 0], type='', swap='kpt-8'), + 25: dict(name='kpt-25', id=25, color=[255, 0, 0], type='', swap='kpt-7'), + 26: dict(name='kpt-26', id=26, color=[255, 0, 0], type='', swap='kpt-6'), + 27: dict(name='kpt-27', id=27, color=[255, 0, 0], type='', swap='kpt-5'), + 28: dict(name='kpt-28', id=28, color=[255, 0, 0], type='', swap='kpt-4'), + 29: dict(name='kpt-29', id=29, color=[255, 0, 0], type='', swap='kpt-3'), + 30: dict(name='kpt-30', id=30, color=[255, 0, 0], type='', swap='kpt-2'), + 31: dict(name='kpt-31', id=31, color=[255, 0, 0], type='', swap='kpt-1'), + 32: dict(name='kpt-32', id=32, color=[255, 0, 0], type='', swap='kpt-0'), + 33: dict(name='kpt-33', id=33, color=[255, 0, 0], type='', swap='kpt-46'), + 34: dict(name='kpt-34', id=34, color=[255, 0, 0], type='', swap='kpt-45'), + 35: dict(name='kpt-35', id=35, color=[255, 0, 0], type='', swap='kpt-44'), + 36: dict(name='kpt-36', id=36, color=[255, 0, 0], type='', swap='kpt-43'), + 37: dict(name='kpt-37', id=37, color=[255, 0, 0], type='', swap='kpt-42'), + 38: dict(name='kpt-38', id=38, color=[255, 0, 0], type='', swap='kpt-50'), + 39: dict(name='kpt-39', id=39, color=[255, 0, 0], type='', swap='kpt-49'), + 40: dict(name='kpt-40', id=40, color=[255, 0, 0], type='', swap='kpt-48'), + 41: dict(name='kpt-41', id=41, color=[255, 0, 0], type='', swap='kpt-47'), + 42: dict(name='kpt-42', id=42, color=[255, 0, 0], type='', swap='kpt-37'), + 43: dict(name='kpt-43', id=43, color=[255, 0, 0], type='', swap='kpt-36'), + 44: dict(name='kpt-44', id=44, color=[255, 0, 0], type='', swap='kpt-35'), + 45: dict(name='kpt-45', id=45, color=[255, 0, 0], type='', swap='kpt-34'), + 46: dict(name='kpt-46', id=46, color=[255, 0, 0], type='', swap='kpt-33'), + 47: dict(name='kpt-47', id=47, color=[255, 0, 0], type='', swap='kpt-41'), + 48: dict(name='kpt-48', id=48, color=[255, 0, 0], type='', swap='kpt-40'), + 49: dict(name='kpt-49', id=49, color=[255, 0, 0], type='', swap='kpt-39'), + 50: dict(name='kpt-50', id=50, color=[255, 0, 0], type='', swap='kpt-38'), + 51: dict(name='kpt-51', id=51, color=[255, 0, 0], type='', swap=''), + 52: dict(name='kpt-52', id=52, color=[255, 0, 0], type='', swap=''), + 53: dict(name='kpt-53', id=53, color=[255, 0, 0], type='', swap=''), + 54: dict(name='kpt-54', id=54, color=[255, 0, 0], type='', swap=''), + 55: dict(name='kpt-55', id=55, color=[255, 0, 0], type='', swap='kpt-59'), + 56: dict(name='kpt-56', id=56, color=[255, 0, 0], type='', swap='kpt-58'), + 57: dict(name='kpt-57', id=57, color=[255, 0, 0], type='', swap=''), + 58: dict(name='kpt-58', id=58, color=[255, 0, 0], type='', swap='kpt-56'), + 59: dict(name='kpt-59', id=59, color=[255, 0, 0], type='', swap='kpt-55'), + 60: dict(name='kpt-60', id=60, color=[255, 0, 0], type='', swap='kpt-72'), + 61: dict(name='kpt-61', id=61, color=[255, 0, 0], type='', swap='kpt-71'), + 62: dict(name='kpt-62', id=62, color=[255, 0, 0], type='', swap='kpt-70'), + 63: dict(name='kpt-63', id=63, color=[255, 0, 0], type='', swap='kpt-69'), + 64: dict(name='kpt-64', id=64, color=[255, 0, 0], type='', swap='kpt-68'), + 65: dict(name='kpt-65', id=65, color=[255, 0, 0], type='', swap='kpt-75'), + 66: dict(name='kpt-66', id=66, color=[255, 0, 0], type='', swap='kpt-74'), + 67: dict(name='kpt-67', id=67, color=[255, 0, 0], type='', swap='kpt-73'), + 68: dict(name='kpt-68', id=68, color=[255, 0, 0], type='', swap='kpt-64'), + 69: dict(name='kpt-69', id=69, color=[255, 0, 0], type='', swap='kpt-63'), + 70: dict(name='kpt-70', id=70, color=[255, 0, 0], type='', swap='kpt-62'), + 71: dict(name='kpt-71', id=71, color=[255, 0, 0], type='', swap='kpt-61'), + 72: dict(name='kpt-72', id=72, color=[255, 0, 0], type='', swap='kpt-60'), + 73: dict(name='kpt-73', id=73, color=[255, 0, 0], type='', swap='kpt-67'), + 74: dict(name='kpt-74', id=74, color=[255, 0, 0], type='', swap='kpt-66'), + 75: dict(name='kpt-75', id=75, color=[255, 0, 0], type='', swap='kpt-65'), + 76: dict(name='kpt-76', id=76, color=[255, 0, 0], type='', swap='kpt-82'), + 77: dict(name='kpt-77', id=77, color=[255, 0, 0], type='', swap='kpt-81'), + 78: dict(name='kpt-78', id=78, color=[255, 0, 0], type='', swap='kpt-80'), + 79: dict(name='kpt-79', id=79, color=[255, 0, 0], type='', swap=''), + 80: dict(name='kpt-80', id=80, color=[255, 0, 0], type='', swap='kpt-78'), + 81: dict(name='kpt-81', id=81, color=[255, 0, 0], type='', swap='kpt-77'), + 82: dict(name='kpt-82', id=82, color=[255, 0, 0], type='', swap='kpt-76'), + 83: dict(name='kpt-83', id=83, color=[255, 0, 0], type='', swap='kpt-87'), + 84: dict(name='kpt-84', id=84, color=[255, 0, 0], type='', swap='kpt-86'), + 85: dict(name='kpt-85', id=85, color=[255, 0, 0], type='', swap=''), + 86: dict(name='kpt-86', id=86, color=[255, 0, 0], type='', swap='kpt-84'), + 87: dict(name='kpt-87', id=87, color=[255, 0, 0], type='', swap='kpt-83'), + 88: dict(name='kpt-88', id=88, color=[255, 0, 0], type='', swap='kpt-92'), + 89: dict(name='kpt-89', id=89, color=[255, 0, 0], type='', swap='kpt-91'), + 90: dict(name='kpt-90', id=90, color=[255, 0, 0], type='', swap=''), + 91: dict(name='kpt-91', id=91, color=[255, 0, 0], type='', swap='kpt-89'), + 92: dict(name='kpt-92', id=92, color=[255, 0, 0], type='', swap='kpt-88'), + 93: dict(name='kpt-93', id=93, color=[255, 0, 0], type='', swap='kpt-95'), + 94: dict(name='kpt-94', id=94, color=[255, 0, 0], type='', swap=''), + 95: dict(name='kpt-95', id=95, color=[255, 0, 0], type='', swap='kpt-93'), + 96: dict(name='kpt-96', id=96, color=[255, 0, 0], type='', swap='kpt-97'), + 97: dict(name='kpt-97', id=97, color=[255, 0, 0], type='', swap='kpt-96') + } + + +def unpickle(file): + import pickle + with open(file, 'rb') as fo: + dict = pickle.load(fo, encoding='bytes') + return dict + + +if __name__ == '__main__': + # Set argument (data directory) + parser = argparse.ArgumentParser(description="Parser for WFLW dataset downloader.") + parser.add_argument('--dir', type=str, default=DEFAULT_DATA_DIR) + args = parser.parse_args() + + # Download wflw dataset + os.makedirs(DOWNLOAD_DIR, exist_ok=True) + download_path = Path(DOWNLOAD_DIR) / 'WFLW_images.tar.gz' + if download_path.exists(): + print(f'Download path {download_path} already exists! download step is skipped.') + else: + torch.hub.download_url_to_file(WFLW_IMAGES_URL, download_path) + + download_path = Path(DOWNLOAD_DIR) / 'WFLW_annotations.tar.gz' + if download_path.exists(): + print(f'Download path {download_path} already exists! download step is skipped.') + else: + torch.hub.download_url_to_file(WFLW_ANNOTATIONS_URL, download_path) + + # Set base directory + wflw_path = Path(args.dir) / 'wflw' + os.makedirs(wflw_path, exist_ok=True) + + # Extract images + ap = tarfile.open(Path(DOWNLOAD_DIR) / 'WFLW_images.tar.gz') + ap.extractall(wflw_path) + ap.close() + + # Extract annotations + ap = tarfile.open(Path(DOWNLOAD_DIR) / 'WFLW_annotations.tar.gz') + ap.extractall(wflw_path) + ap.close() + + ori_images_root = wflw_path / 'WFLW_images' + ori_ann_root = wflw_path / 'WFLW_annotations' + + # Train + phase = 'train' + + train_image_dir = wflw_path / 'images' / 'train' + train_label_dir = wflw_path / 'labels' / 'train' + os.makedirs(train_image_dir, exist_ok=True) + os.makedirs(train_label_dir, exist_ok=True) + + with open(ori_ann_root / 'list_98pt_rect_attr_train_test' / 'list_98pt_rect_attr_train.txt') as f: + train_lines = f.readlines() + + train_dict = {} + for line in train_lines: + line = line.strip() + ann = line.split(' ') + + keypoints = ann[:-11] + box = ann[-11:-7] + attributes = ann[-7:-1] + img = ann[-1] + + keypoints = np.array(keypoints) + keypoints = keypoints.reshape(-1, 2) + keypoints = np.hstack((keypoints, np.ones((len(keypoints), 1)))) + keypoints = keypoints.ravel() + keypoints = keypoints.tolist() + + if img not in train_dict: + train_dict[img] = [] + + sample = ' '.join(keypoints) + sample += ' ' + ' '.join(box) + + train_dict[img].append(sample) + + for key, val in train_dict.items(): + src_img = key + img = Path(key.split('/')[-1]) + label = Path(img.stem + '.txt') + sample = '\n'.join(val) + + shutil.copy(ori_images_root / src_img, train_image_dir / img) + with open(train_label_dir / label, 'w') as f: + f.write(sample) + f.close() + + # Validation + phase = 'valid' + + valid_image_dir = wflw_path / 'images' / 'valid' + valid_label_dir = wflw_path / 'labels' / 'valid' + os.makedirs(valid_image_dir, exist_ok=True) + os.makedirs(valid_label_dir, exist_ok=True) + + with open(ori_ann_root / 'list_98pt_rect_attr_train_test' / 'list_98pt_rect_attr_test.txt') as f: + val_lines = f.readlines() + + val_dict = {} + for line in val_lines: + line = line.strip() + ann = line.split(' ') + + keypoints = ann[:-11] + box = ann[-11:-7] + attributes = ann[-7:-1] + img = ann[-1] + + keypoints = np.array(keypoints) + keypoints = keypoints.reshape(-1, 2) + keypoints = np.hstack((keypoints, np.ones((len(keypoints), 1)))) + keypoints = keypoints.ravel() + keypoints = keypoints.tolist() + + if img not in val_dict: + val_dict[img] = [] + + sample = ' '.join(keypoints) + sample += ' ' + ' '.join(box) + + val_dict[img].append(sample) + + for key, val in val_dict.items(): + src_img = key + img = Path(key.split('/')[-1]) + label = Path(img.stem + '.txt') + sample = '\n'.join(val) + + shutil.copy(ori_images_root / src_img, valid_image_dir / img) + with open(valid_label_dir / label, 'w') as f: + f.write(sample) + f.close() + + # Build id_mapping + id_mapping = [] + for key, val in KEYPOINT_INFO.items(): + swap = val['swap'] + if swap == '': + swap = key + + id_mapping.append(dict(name=val['name'], skeleton=None, swap=swap)) + + with open(wflw_path / 'id_mapping.json', 'w') as f: + json.dump(id_mapping, f) + + try: + shutil.rmtree(ori_images_root) + shutil.rmtree(ori_ann_root) + except OSError as e: + print(e) From c9537f943cb4894ba9fb6e63bc66809f7d0b8df7 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Thu, 2 May 2024 05:14:29 +0000 Subject: [PATCH 76/91] Fix pose estimation load_id_mapping --- .../dataloaders/pose_estimation.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/netspresso_trainer/dataloaders/pose_estimation.py b/src/netspresso_trainer/dataloaders/pose_estimation.py index ade735317..2bafc31b2 100644 --- a/src/netspresso_trainer/dataloaders/pose_estimation.py +++ b/src/netspresso_trainer/dataloaders/pose_estimation.py @@ -3,11 +3,13 @@ from multiprocessing.pool import ThreadPool from pathlib import Path from typing import Dict, List, Optional, Tuple, Union +import json import numpy as np import PIL.Image as Image import torch.distributed as dist from loguru import logger +from omegaconf import ListConfig from .base import BaseCustomDataset, BaseSampleLoader from .utils.constants import IMG_EXTENSIONS @@ -50,8 +52,17 @@ def load_data(self, split='train'): return images_and_targets def load_id_mapping(self): - # TODO: Get id_mapping from txt file - return list(self.conf_data.id_mapping) + root_path = Path(self.conf_data.path.root) + + if isinstance(self.conf_data.id_mapping, ListConfig): + return list(self.conf_data.id_mapping) + elif isinstance(self.conf_data.id_mapping, str): + id_mapping_path = root_path / self.conf_data.id_mapping + with open(id_mapping_path, 'r') as f: + id_mapping = json.load(f) + return id_mapping + else: + raise ValueError(f"Invalid id_mapping type: {type(self.conf_data.id_mapping)}") def load_class_map(self, id_mapping): idx_to_class: Dict[int, str] = dict(enumerate(id_mapping)) From 270b1fef9c25d91e74ca8cd3e03663339444671c Mon Sep 17 00:00:00 2001 From: tree89 Date: Thu, 2 May 2024 14:27:16 +0900 Subject: [PATCH 77/91] Add install command in Dockerfile. --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 93b25250d..363d3ce73 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,3 +30,4 @@ COPY . /home/appuser/netspresso-trainer RUN pip install -r requirements.txt && rm -rf /root/.cache/pip RUN pip install -r requirements-optional.txt && rm -rf /root/.cache/pip +RUN python3 -m pip install -e . From 82462546cc388d020afca33cee4ff07a0cb32605 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Thu, 2 May 2024 05:44:45 +0000 Subject: [PATCH 78/91] Fix swap value error --- tools/open_dataset_tool/wflw.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/open_dataset_tool/wflw.py b/tools/open_dataset_tool/wflw.py index 555f8ce44..817834ef6 100644 --- a/tools/open_dataset_tool/wflw.py +++ b/tools/open_dataset_tool/wflw.py @@ -258,7 +258,7 @@ def unpickle(file): for key, val in KEYPOINT_INFO.items(): swap = val['swap'] if swap == '': - swap = key + swap = val['name'] id_mapping.append(dict(name=val['name'], skeleton=None, swap=swap)) From f21c95d1bda94c5f7464750d316e43a0e6a52883 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Thu, 2 May 2024 05:44:56 +0000 Subject: [PATCH 79/91] Update wflw config --- config/data/local/wflw.yaml | 400 +----------------------------------- 1 file changed, 4 insertions(+), 396 deletions(-) diff --git a/config/data/local/wflw.yaml b/config/data/local/wflw.yaml index f8973f653..ef79a5982 100644 --- a/config/data/local/wflw.yaml +++ b/config/data/local/wflw.yaml @@ -3,410 +3,18 @@ data: task: pose_estimation format: local # local, huggingface path: - root: ../data/WFLW # dataset root + root: ./data/wflw # dataset root train: image: images/train # directory for training images label: labels/train # directory for training labels valid: - image: images/val # directory for valid images - label: labels/val # directory for valid labels + image: images/valid # directory for valid images + label: labels/valid # directory for valid labels test: image: ~ # directory for test images label: ~ # directory for test labels pattern: image: ~ label: ~ - id_mapping: - - - name: '0' - skeleton: ~ - swap: '32' - - - name: '1' - skeleton: ~ - swap: '31' - - - name: '2' - skeleton: ~ - swap: '30' - - - name: '3' - skeleton: ~ - swap: '29' - - - name: '4' - skeleton: ~ - swap: '28' - - - name: '5' - skeleton: ~ - swap: '27' - - - name: '6' - skeleton: ~ - swap: '26' - - - name: '7' - skeleton: ~ - swap: '25' - - - name: '8' - skeleton: ~ - swap: '24' - - - name: '9' - skeleton: ~ - swap: '23' - - - name: '10' - skeleton: ~ - swap: '22' - - - name: '11' - skeleton: ~ - swap: '21' - - - name: '12' - skeleton: ~ - swap: '20' - - - name: '13' - skeleton: ~ - swap: '19' - - - name: '14' - skeleton: ~ - swap: '18' - - - name: '15' - skeleton: ~ - swap: '17' - - - name: '16' - skeleton: ~ - swap: '16' - - - name: '17' - skeleton: ~ - swap: '15' - - - name: '18' - skeleton: ~ - swap: '14' - - - name: '19' - skeleton: ~ - swap: '13' - - - name: '20' - skeleton: ~ - swap: '12' - - - name: '21' - skeleton: ~ - swap: '11' - - - name: '22' - skeleton: ~ - swap: '10' - - - name: '23' - skeleton: ~ - swap: '9' - - - name: '24' - skeleton: ~ - swap: '8' - - - name: '25' - skeleton: ~ - swap: '7' - - - name: '26' - skeleton: ~ - swap: '6' - - - name: '27' - skeleton: ~ - swap: '5' - - - name: '28' - skeleton: ~ - swap: '4' - - - name: '29' - skeleton: ~ - swap: '3' - - - name: '30' - skeleton: ~ - swap: '2' - - - name: '31' - skeleton: ~ - swap: '1' - - - name: '32' - skeleton: ~ - swap: '0' - - - name: '33' - skeleton: ~ - swap: '46' - - - name: '34' - skeleton: ~ - swap: '45' - - - name: '35' - skeleton: ~ - swap: '44' - - - name: '36' - skeleton: ~ - swap: '43' - - - name: '37' - skeleton: ~ - swap: '42' - - - name: '38' - skeleton: ~ - swap: '50' - - - name: '39' - skeleton: ~ - swap: '49' - - - name: '40' - skeleton: ~ - swap: '48' - - - name: '41' - skeleton: ~ - swap: '47' - - - name: '42' - skeleton: ~ - swap: '37' - - - name: '43' - skeleton: ~ - swap: '36' - - - name: '44' - skeleton: ~ - swap: '35' - - - name: '45' - skeleton: ~ - swap: '34' - - - name: '46' - skeleton: ~ - swap: '33' - - - name: '47' - skeleton: ~ - swap: '41' - - - name: '48' - skeleton: ~ - swap: '40' - - - name: '49' - skeleton: ~ - swap: '39' - - - name: '50' - skeleton: ~ - swap: '38' - - - name: '51' - skeleton: ~ - swap: '51' - - - name: '52' - skeleton: ~ - swap: '52' - - - name: '53' - skeleton: ~ - swap: '53' - - - name: '54' - skeleton: ~ - swap: '54' - - - name: '55' - skeleton: ~ - swap: '59' - - - name: '56' - skeleton: ~ - swap: '58' - - - name: '57' - skeleton: ~ - swap: '57' - - - name: '58' - skeleton: ~ - swap: '56' - - - name: '59' - skeleton: ~ - swap: '55' - - - name: '60' - skeleton: ~ - swap: '72' - - - name: '61' - skeleton: ~ - swap: '71' - - - name: '62' - skeleton: ~ - swap: '70' - - - name: '63' - skeleton: ~ - swap: '69' - - - name: '64' - skeleton: ~ - swap: '68' - - - name: '65' - skeleton: ~ - swap: '75' - - - name: '66' - skeleton: ~ - swap: '74' - - - name: '67' - skeleton: ~ - swap: '73' - - - name: '68' - skeleton: ~ - swap: '64' - - - name: '69' - skeleton: ~ - swap: '63' - - - name: '70' - skeleton: ~ - swap: '62' - - - name: '71' - skeleton: ~ - swap: '61' - - - name: '72' - skeleton: ~ - swap: '60' - - - name: '73' - skeleton: ~ - swap: '67' - - - name: '74' - skeleton: ~ - swap: '66' - - - name: '75' - skeleton: ~ - swap: '65' - - - name: '76' - skeleton: ~ - swap: '82' - - - name: '77' - skeleton: ~ - swap: '81' - - - name: '78' - skeleton: ~ - swap: '80' - - - name: '79' - skeleton: ~ - swap: '79' - - - name: '80' - skeleton: ~ - swap: '78' - - - name: '81' - skeleton: ~ - swap: '77' - - - name: '82' - skeleton: ~ - swap: '76' - - - name: '83' - skeleton: ~ - swap: '87' - - - name: '84' - skeleton: ~ - swap: '86' - - - name: '85' - skeleton: ~ - swap: '85' - - - name: '86' - skeleton: ~ - swap: '84' - - - name: '87' - skeleton: ~ - swap: '83' - - - name: '88' - skeleton: ~ - swap: '92' - - - name: '89' - skeleton: ~ - swap: '91' - - - name: '90' - skeleton: ~ - swap: '90' - - - name: '91' - skeleton: ~ - swap: '89' - - - name: '92' - skeleton: ~ - swap: '88' - - - name: '93' - skeleton: ~ - swap: '95' - - - name: '94' - skeleton: ~ - swap: '94' - - - name: '95' - skeleton: ~ - swap: '93' - - - name: '96' - skeleton: ~ - swap: '97' - - - name: '97' - skeleton: ~ - swap: '96' + id_mapping: id_mapping.json pallete: ~ \ No newline at end of file From bb684d2fb8a9f416e403aba0cf46e7ddd771a82a Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Thu, 2 May 2024 05:48:23 +0000 Subject: [PATCH 80/91] Update docs --- README.md | 4 ++++ docs/getting_started/dataset_preparation/local.md | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/README.md b/README.md index 0c29fb431..7437de058 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,10 @@ If you are interested in utilizing open datasets, you can use them by following - [COCO 2017](https://github.com/Nota-NetsPresso/netspresso-trainer/blob/dev/tools/open_dataset_tool/coco2017.py) +### Pose estimation + +- [WFLW](https://github.com/Nota-NetsPresso/netspresso-trainer/blob/dev/tools/open_dataset_tool/wflw.py) + ## Dataset preparation (Huggingface) NetsPresso Trainer is also compatible with huggingface dataset. To use datasets of huggingface, please check [instructions in our documentations](https://nota-netspresso.github.io/netspresso-trainer/getting_started/dataset_preparation/huggingface/). This enables to utilize a wide range of pre-built datasets which are beneficial for various training scenarios. diff --git a/docs/getting_started/dataset_preparation/local.md b/docs/getting_started/dataset_preparation/local.md index 381f74d5f..a16e451ed 100644 --- a/docs/getting_started/dataset_preparation/local.md +++ b/docs/getting_started/dataset_preparation/local.md @@ -144,6 +144,18 @@ COCO 2017 dataset will be automatically downloaded to `./data/download`. After e python ./tools/open_dataset_tool/coco2017.py --dir ./data ``` +### Pose estimation + +#### WFLW + +Run `wflw.py` python file with your dataset directory as an argument. + +WFLW dataset will be automatically downloaded to `./data/download`. After executing scripts, you can use [pre-defined configuration](https://github.com/Nota-NetsPresso/netspresso-trainer/blob/dev/config/data/local/wflw.yaml). + +```bash +python ./tools/open_dataset_tool/wflw.py --dir ./data +``` + ## Run NetsPresso Trainer Now you can run NetsPresso Trainer with your local dataset! From 5560997f080790f18dc3f873c23824725cc96b10 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Thu, 2 May 2024 05:48:52 +0000 Subject: [PATCH 81/91] Ruff fix --- src/netspresso_trainer/dataloaders/classification.py | 2 +- src/netspresso_trainer/dataloaders/detection.py | 2 +- src/netspresso_trainer/dataloaders/pose_estimation.py | 2 +- src/netspresso_trainer/dataloaders/segmentation.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/netspresso_trainer/dataloaders/classification.py b/src/netspresso_trainer/dataloaders/classification.py index cad255ea8..55d559aa8 100644 --- a/src/netspresso_trainer/dataloaders/classification.py +++ b/src/netspresso_trainer/dataloaders/classification.py @@ -1,10 +1,10 @@ +import json import os from functools import partial from itertools import chain from multiprocessing.pool import ThreadPool from pathlib import Path from typing import Dict, List, Optional, Tuple, Union -import json import PIL.Image as Image import torch.distributed as dist diff --git a/src/netspresso_trainer/dataloaders/detection.py b/src/netspresso_trainer/dataloaders/detection.py index e815bef34..008cc79cc 100644 --- a/src/netspresso_trainer/dataloaders/detection.py +++ b/src/netspresso_trainer/dataloaders/detection.py @@ -1,10 +1,10 @@ +import json import os from functools import partial from itertools import chain from multiprocessing.pool import ThreadPool from pathlib import Path from typing import Dict, List, Optional, Tuple, Union -import json import numpy as np import PIL.Image as Image diff --git a/src/netspresso_trainer/dataloaders/pose_estimation.py b/src/netspresso_trainer/dataloaders/pose_estimation.py index 2bafc31b2..0c82b5297 100644 --- a/src/netspresso_trainer/dataloaders/pose_estimation.py +++ b/src/netspresso_trainer/dataloaders/pose_estimation.py @@ -1,9 +1,9 @@ +import json from functools import partial from itertools import chain from multiprocessing.pool import ThreadPool from pathlib import Path from typing import Dict, List, Optional, Tuple, Union -import json import numpy as np import PIL.Image as Image diff --git a/src/netspresso_trainer/dataloaders/segmentation.py b/src/netspresso_trainer/dataloaders/segmentation.py index 29d4ada79..fd6acee64 100644 --- a/src/netspresso_trainer/dataloaders/segmentation.py +++ b/src/netspresso_trainer/dataloaders/segmentation.py @@ -1,10 +1,10 @@ +import json import os from functools import partial from itertools import chain from multiprocessing.pool import ThreadPool from pathlib import Path from typing import Dict, List, Literal, Optional, Tuple, Union -import json import numpy as np import PIL.Image as Image From 9e1d657c0ddd188a3f3f384d4e119b7f9012f62b Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Thu, 2 May 2024 05:57:08 +0000 Subject: [PATCH 82/91] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f34566ef1..1920279a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ ## Bug Fixes: - Fix test directory check line by `@illian01` in [PR 428](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/428) +- Fix Dockerfile installation commandline `@cbpark-nota` in [PR 434](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/434) ## Breaking Changes: From c4b8b0962e0db0746627b0842f8ce5d1a42576e8 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Thu, 2 May 2024 06:02:06 +0000 Subject: [PATCH 83/91] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1920279a0..2ce72a8b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ - Add dataset validation step and refactoring data modules by `@illian01` in [PR 417](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/417), [PR 419](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/419) - Add various dataset examples including automatic open dataset format converter by `@illian01` in [PR 430](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/430) -- Allow using text file path for the `id_mapping` field (for classification and detection) by `@illian01` in [PR 432](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/432) +- Allow using text file path for the `id_mapping` field by `@illian01` in [PR 432](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/432), [PR 435](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/435) ## Bug Fixes: From 0c85dbe0f323275c9f812331934cb016da26e947 Mon Sep 17 00:00:00 2001 From: tree89 Date: Thu, 2 May 2024 15:25:41 +0900 Subject: [PATCH 84/91] Update docs to simple use. --- docs/getting_started/simple_use.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/getting_started/simple_use.md b/docs/getting_started/simple_use.md index 8c8949140..075e3f905 100644 --- a/docs/getting_started/simple_use.md +++ b/docs/getting_started/simple_use.md @@ -14,10 +14,10 @@ Then, train your model with your own configuraiton: ```bash python train.py\ - --data config/data/beans.yaml\ + --data config/data/huggingface/beans.yaml\ --augmentation config/augmentation/classification.yaml\ --model config/model/resnet/resnet50-classification.yaml\ - --training config/training/classification.yaml\ + --training config/training.yaml\ --logging config/logging.yaml\ --environment config/environment.yaml ``` @@ -26,10 +26,10 @@ Or you can start NetsPresso Trainer by just executing console script which has s ```bash netspresso-train\ - --data config/data/beans.yaml\ + --data config/data/huggingface/beans.yaml\ --augmentation config/augmentation/classification.yaml\ --model config/model/resnet/resnet50-classification.yaml\ - --training config/training/classification.yaml\ + --training config/training.yaml\ --logging config/logging.yaml\ --environment config/environment.yaml ``` @@ -55,7 +55,7 @@ Then, evaluate your model with your own configuraiton: ```bash python evaluation.py\ - --data config/data/beans.yaml\ + --data config/data/huggingface/beans.yaml\ --augmentation config/augmentation/classification.yaml\ --model config/model/resnet/resnet50-classification.yaml\ --logging config/logging.yaml\ @@ -79,7 +79,7 @@ Then, inference your dataset: ```bash python inference.py\ - --data config/data/beans.yaml\ + --data config/data/huggingface/beans.yaml\ --augmentation config/augmentation/classification.yaml\ --model config/model/resnet/resnet50-classification.yaml\ --logging config/logging.yaml\ From 81802fbfa7c201834fbe9eeb9991649a1197b490 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Thu, 2 May 2024 09:02:39 +0000 Subject: [PATCH 85/91] Update configs --- config/augmentation/pose_estimation.yaml | 1 - config/augmentation/segmentation.yaml | 1 - config/augmentation/template/common.yaml | 31 +----------- .../augmentation.yaml | 21 ++++++++ .../data.yaml | 16 ++++++ .../environment.yaml | 5 ++ .../logging.yaml | 10 ++++ .../model.yaml | 44 ++++++++++++++++ .../training.yaml | 14 ++++++ .../augmentation.yaml | 21 ++++++++ .../data.yaml | 16 ++++++ .../environment.yaml | 5 ++ .../logging.yaml | 10 ++++ .../model.yaml | 44 ++++++++++++++++ .../training.yaml | 14 ++++++ .../augmentation.yaml | 33 ++++++++++++ .../data.yaml | 16 ++++++ .../environment.yaml | 5 ++ .../logging.yaml | 10 ++++ .../model.yaml | 44 ++++++++++++++++ .../training.yaml | 15 ++++++ .../augmentation.yaml | 50 +++++++++++++++++++ .../detection-coco2017-yolox_s/data.yaml | 21 ++++++++ .../environment.yaml | 5 ++ .../detection-coco2017-yolox_s/logging.yaml | 10 ++++ .../detection-coco2017-yolox_s/model.yaml | 37 ++++++++++++++ .../detection-coco2017-yolox_s/training.yaml | 18 +++++++ config/training.yaml | 1 + 28 files changed, 486 insertions(+), 32 deletions(-) create mode 100644 config/benchmark_examples/classification-imagenet1k-resnet18/augmentation.yaml create mode 100644 config/benchmark_examples/classification-imagenet1k-resnet18/data.yaml create mode 100644 config/benchmark_examples/classification-imagenet1k-resnet18/environment.yaml create mode 100644 config/benchmark_examples/classification-imagenet1k-resnet18/logging.yaml create mode 100644 config/benchmark_examples/classification-imagenet1k-resnet18/model.yaml create mode 100644 config/benchmark_examples/classification-imagenet1k-resnet18/training.yaml create mode 100644 config/benchmark_examples/classification-imagenet1k-resnet34/augmentation.yaml create mode 100644 config/benchmark_examples/classification-imagenet1k-resnet34/data.yaml create mode 100644 config/benchmark_examples/classification-imagenet1k-resnet34/environment.yaml create mode 100644 config/benchmark_examples/classification-imagenet1k-resnet34/logging.yaml create mode 100644 config/benchmark_examples/classification-imagenet1k-resnet34/model.yaml create mode 100644 config/benchmark_examples/classification-imagenet1k-resnet34/training.yaml create mode 100644 config/benchmark_examples/classification-imagenet1k-resnet50/augmentation.yaml create mode 100644 config/benchmark_examples/classification-imagenet1k-resnet50/data.yaml create mode 100644 config/benchmark_examples/classification-imagenet1k-resnet50/environment.yaml create mode 100644 config/benchmark_examples/classification-imagenet1k-resnet50/logging.yaml create mode 100644 config/benchmark_examples/classification-imagenet1k-resnet50/model.yaml create mode 100644 config/benchmark_examples/classification-imagenet1k-resnet50/training.yaml create mode 100644 config/benchmark_examples/detection-coco2017-yolox_s/augmentation.yaml create mode 100644 config/benchmark_examples/detection-coco2017-yolox_s/data.yaml create mode 100644 config/benchmark_examples/detection-coco2017-yolox_s/environment.yaml create mode 100644 config/benchmark_examples/detection-coco2017-yolox_s/logging.yaml create mode 100644 config/benchmark_examples/detection-coco2017-yolox_s/model.yaml create mode 100644 config/benchmark_examples/detection-coco2017-yolox_s/training.yaml diff --git a/config/augmentation/pose_estimation.yaml b/config/augmentation/pose_estimation.yaml index 56549b55e..9d6cb73ee 100644 --- a/config/augmentation/pose_estimation.yaml +++ b/config/augmentation/pose_estimation.yaml @@ -1,5 +1,4 @@ augmentation: - img_size: &img_size 256 train: - name: randomhorizontalflip diff --git a/config/augmentation/segmentation.yaml b/config/augmentation/segmentation.yaml index 71b48af13..cddd99fa6 100644 --- a/config/augmentation/segmentation.yaml +++ b/config/augmentation/segmentation.yaml @@ -1,5 +1,4 @@ augmentation: - img_size: &img_size 512 train: - name: randomresizedcrop diff --git a/config/augmentation/template/common.yaml b/config/augmentation/template/common.yaml index 5b7150486..7da789c00 100644 --- a/config/augmentation/template/common.yaml +++ b/config/augmentation/template/common.yaml @@ -1,32 +1,3 @@ augmentation: - train: - - - name: randomresizedcrop - size: ~ - sclale: ~ - ratio: ~ - interpolation: bilinear - - - name: randomhorizontalflip - p: ~ - - - name: randomverticalflip - p: ~ - - - name: colorjitter - brightness: ~ - contrast: ~ - saturation: ~ - hue: ~ - p: ~ - - - name: resize - size: ~ - interpolation: ~ - max_size: ~ - - - name: pad - padding: ~ - fill: ~ - padding_mode: ~ + train: ~ inference: ~ \ No newline at end of file diff --git a/config/benchmark_examples/classification-imagenet1k-resnet18/augmentation.yaml b/config/benchmark_examples/classification-imagenet1k-resnet18/augmentation.yaml new file mode 100644 index 000000000..e9afbb4aa --- /dev/null +++ b/config/benchmark_examples/classification-imagenet1k-resnet18/augmentation.yaml @@ -0,0 +1,21 @@ +augmentation: + train: + - + name: randomresizedcrop + size: 256 + scale: [0.08, 1.0] + ratio: [0.75, 1.33] + interpolation: bilinear + - + name: randomhorizontalflip + p: 0.5 + inference: + - + name: resize + size: [256, 256] + interpolation: bilinear + max_size: ~ + resize_criteria: ~ + - + name: centercrop + size: 224 diff --git a/config/benchmark_examples/classification-imagenet1k-resnet18/data.yaml b/config/benchmark_examples/classification-imagenet1k-resnet18/data.yaml new file mode 100644 index 000000000..4364862ed --- /dev/null +++ b/config/benchmark_examples/classification-imagenet1k-resnet18/data.yaml @@ -0,0 +1,16 @@ +data: + name: IMAGENET1K + task: classification + format: local # local, huggingface + path: + root: ./data/imagenet1k # dataset root + train: + image: images/train # directory for training images + label: labels/imagenet_train.csv # directory for training labels or csv file + valid: + image: images/valid # directory for valid images + label: labels/imagenet_valid.csv # directory for valid labels or csv file + test: + image: ~ + label: ~ + id_mapping: id_mapping.json \ No newline at end of file diff --git a/config/benchmark_examples/classification-imagenet1k-resnet18/environment.yaml b/config/benchmark_examples/classification-imagenet1k-resnet18/environment.yaml new file mode 100644 index 000000000..a24602d60 --- /dev/null +++ b/config/benchmark_examples/classification-imagenet1k-resnet18/environment.yaml @@ -0,0 +1,5 @@ +environment: + seed: 1 + num_workers: 4 + gpus: 0, 1, 2, 3, 4, 5, 6, 7 + batch_size: 32 # Batch size per gpu \ No newline at end of file diff --git a/config/benchmark_examples/classification-imagenet1k-resnet18/logging.yaml b/config/benchmark_examples/classification-imagenet1k-resnet18/logging.yaml new file mode 100644 index 000000000..384e938c0 --- /dev/null +++ b/config/benchmark_examples/classification-imagenet1k-resnet18/logging.yaml @@ -0,0 +1,10 @@ +logging: + project_id: ~ + output_dir: ./outputs + tensorboard: true + image: true + stdout: true + save_optimizer_state: true + onnx_input_size: [224, 224] + validation_epoch: &validation_epoch 5 + save_checkpoint_epoch: *validation_epoch # Multiplier of `validation_epoch`. \ No newline at end of file diff --git a/config/benchmark_examples/classification-imagenet1k-resnet18/model.yaml b/config/benchmark_examples/classification-imagenet1k-resnet18/model.yaml new file mode 100644 index 000000000..bef716a26 --- /dev/null +++ b/config/benchmark_examples/classification-imagenet1k-resnet18/model.yaml @@ -0,0 +1,44 @@ +model: + task: classification + name: resnet18 + checkpoint: + use_pretrained: False + load_head: False + path: ~ + fx_model_path: ~ + optimizer_path: ~ + freeze_backbone: False + architecture: + full: ~ # auto + backbone: + name: resnet + params: + block_type: basicblock + norm_type: batch_norm + stage_params: + - + channels: 64 + num_blocks: 2 + - + channels: 128 + num_blocks: 2 + replace_stride_with_dilation: False + - + channels: 256 + num_blocks: 2 + replace_stride_with_dilation: False + - + channels: 512 + num_blocks: 2 + replace_stride_with_dilation: False + head: + name: fc + params: + num_layers: 1 + intermediate_channels: ~ + act_type: ~ + dropout_prob: 0. + losses: + - criterion: cross_entropy + label_smoothing: 0. + weight: ~ \ No newline at end of file diff --git a/config/benchmark_examples/classification-imagenet1k-resnet18/training.yaml b/config/benchmark_examples/classification-imagenet1k-resnet18/training.yaml new file mode 100644 index 000000000..769a07b37 --- /dev/null +++ b/config/benchmark_examples/classification-imagenet1k-resnet18/training.yaml @@ -0,0 +1,14 @@ +training: + epochs: 90 + mixed_precision: False + ema: ~ + optimizer: + name: sgd + lr: 0.1 + momentum: 0.9 + weight_decay: 0.0001 + nesterov: False + scheduler: + name: step + ites_per_phase: 30 + gamma: 0.1 diff --git a/config/benchmark_examples/classification-imagenet1k-resnet34/augmentation.yaml b/config/benchmark_examples/classification-imagenet1k-resnet34/augmentation.yaml new file mode 100644 index 000000000..e9afbb4aa --- /dev/null +++ b/config/benchmark_examples/classification-imagenet1k-resnet34/augmentation.yaml @@ -0,0 +1,21 @@ +augmentation: + train: + - + name: randomresizedcrop + size: 256 + scale: [0.08, 1.0] + ratio: [0.75, 1.33] + interpolation: bilinear + - + name: randomhorizontalflip + p: 0.5 + inference: + - + name: resize + size: [256, 256] + interpolation: bilinear + max_size: ~ + resize_criteria: ~ + - + name: centercrop + size: 224 diff --git a/config/benchmark_examples/classification-imagenet1k-resnet34/data.yaml b/config/benchmark_examples/classification-imagenet1k-resnet34/data.yaml new file mode 100644 index 000000000..4364862ed --- /dev/null +++ b/config/benchmark_examples/classification-imagenet1k-resnet34/data.yaml @@ -0,0 +1,16 @@ +data: + name: IMAGENET1K + task: classification + format: local # local, huggingface + path: + root: ./data/imagenet1k # dataset root + train: + image: images/train # directory for training images + label: labels/imagenet_train.csv # directory for training labels or csv file + valid: + image: images/valid # directory for valid images + label: labels/imagenet_valid.csv # directory for valid labels or csv file + test: + image: ~ + label: ~ + id_mapping: id_mapping.json \ No newline at end of file diff --git a/config/benchmark_examples/classification-imagenet1k-resnet34/environment.yaml b/config/benchmark_examples/classification-imagenet1k-resnet34/environment.yaml new file mode 100644 index 000000000..fa4d45a21 --- /dev/null +++ b/config/benchmark_examples/classification-imagenet1k-resnet34/environment.yaml @@ -0,0 +1,5 @@ +environment: + seed: 1 + num_workers: 4 + gpus: 0, 1, 2, 3, 4, 5, 6, 7 + batch_size: 23 # Batch size per gpu \ No newline at end of file diff --git a/config/benchmark_examples/classification-imagenet1k-resnet34/logging.yaml b/config/benchmark_examples/classification-imagenet1k-resnet34/logging.yaml new file mode 100644 index 000000000..384e938c0 --- /dev/null +++ b/config/benchmark_examples/classification-imagenet1k-resnet34/logging.yaml @@ -0,0 +1,10 @@ +logging: + project_id: ~ + output_dir: ./outputs + tensorboard: true + image: true + stdout: true + save_optimizer_state: true + onnx_input_size: [224, 224] + validation_epoch: &validation_epoch 5 + save_checkpoint_epoch: *validation_epoch # Multiplier of `validation_epoch`. \ No newline at end of file diff --git a/config/benchmark_examples/classification-imagenet1k-resnet34/model.yaml b/config/benchmark_examples/classification-imagenet1k-resnet34/model.yaml new file mode 100644 index 000000000..77d010d6f --- /dev/null +++ b/config/benchmark_examples/classification-imagenet1k-resnet34/model.yaml @@ -0,0 +1,44 @@ +model: + task: classification + name: resnet34 + checkpoint: + use_pretrained: False + load_head: False + path: ~ + fx_model_path: ~ + optimizer_path: ~ + freeze_backbone: False + architecture: + full: ~ # auto + backbone: + name: resnet + params: + block_type: basicblock + norm_type: batch_norm + stage_params: + - + channels: 64 + num_blocks: 3 + - + channels: 128 + num_blocks: 4 + replace_stride_with_dilation: False + - + channels: 256 + num_blocks: 6 + replace_stride_with_dilation: False + - + channels: 512 + num_blocks: 3 + replace_stride_with_dilation: False + head: + name: fc + params: + num_layers: 1 + intermediate_channels: ~ + act_type: ~ + dropout_prob: 0. + losses: + - criterion: cross_entropy + label_smoothing: 0. + weight: ~ \ No newline at end of file diff --git a/config/benchmark_examples/classification-imagenet1k-resnet34/training.yaml b/config/benchmark_examples/classification-imagenet1k-resnet34/training.yaml new file mode 100644 index 000000000..769a07b37 --- /dev/null +++ b/config/benchmark_examples/classification-imagenet1k-resnet34/training.yaml @@ -0,0 +1,14 @@ +training: + epochs: 90 + mixed_precision: False + ema: ~ + optimizer: + name: sgd + lr: 0.1 + momentum: 0.9 + weight_decay: 0.0001 + nesterov: False + scheduler: + name: step + ites_per_phase: 30 + gamma: 0.1 diff --git a/config/benchmark_examples/classification-imagenet1k-resnet50/augmentation.yaml b/config/benchmark_examples/classification-imagenet1k-resnet50/augmentation.yaml new file mode 100644 index 000000000..6f9d0ed1a --- /dev/null +++ b/config/benchmark_examples/classification-imagenet1k-resnet50/augmentation.yaml @@ -0,0 +1,33 @@ +augmentation: + train: + - + name: randomresizedcrop + size: 176 + scale: [0.08, 1.0] + ratio: [0.75, 1.33] + interpolation: bilinear + - + name: randomhorizontalflip + p: 0.5 + - + name: trivialaugmentwide + num_magnitude_bins: 31 + interpolation: 'bilinear' + - + name: randomerasing + p: 0.1 + - + name: mixing + mixup: [0.2, 1.0] + cutmix: [1.0, 1.0] + inplace: false + inference: + - + name: resize + size: [256, 256] + interpolation: bilinear + max_size: ~ + resize_criteria: ~ + - + name: centercrop + size: 224 diff --git a/config/benchmark_examples/classification-imagenet1k-resnet50/data.yaml b/config/benchmark_examples/classification-imagenet1k-resnet50/data.yaml new file mode 100644 index 000000000..4364862ed --- /dev/null +++ b/config/benchmark_examples/classification-imagenet1k-resnet50/data.yaml @@ -0,0 +1,16 @@ +data: + name: IMAGENET1K + task: classification + format: local # local, huggingface + path: + root: ./data/imagenet1k # dataset root + train: + image: images/train # directory for training images + label: labels/imagenet_train.csv # directory for training labels or csv file + valid: + image: images/valid # directory for valid images + label: labels/imagenet_valid.csv # directory for valid labels or csv file + test: + image: ~ + label: ~ + id_mapping: id_mapping.json \ No newline at end of file diff --git a/config/benchmark_examples/classification-imagenet1k-resnet50/environment.yaml b/config/benchmark_examples/classification-imagenet1k-resnet50/environment.yaml new file mode 100644 index 000000000..c23288df2 --- /dev/null +++ b/config/benchmark_examples/classification-imagenet1k-resnet50/environment.yaml @@ -0,0 +1,5 @@ +environment: + seed: 1 + num_workers: 4 + gpus: 0, 1, 2, 3, 4, 5, 6, 7 + batch_size: 128 # Batch size per gpu \ No newline at end of file diff --git a/config/benchmark_examples/classification-imagenet1k-resnet50/logging.yaml b/config/benchmark_examples/classification-imagenet1k-resnet50/logging.yaml new file mode 100644 index 000000000..65c92999d --- /dev/null +++ b/config/benchmark_examples/classification-imagenet1k-resnet50/logging.yaml @@ -0,0 +1,10 @@ +logging: + project_id: ~ + output_dir: ./outputs + tensorboard: true + image: true + stdout: true + save_optimizer_state: true + onnx_input_size: [224, 224] + validation_epoch: &validation_epoch 10 + save_checkpoint_epoch: *validation_epoch # Multiplier of `validation_epoch`. \ No newline at end of file diff --git a/config/benchmark_examples/classification-imagenet1k-resnet50/model.yaml b/config/benchmark_examples/classification-imagenet1k-resnet50/model.yaml new file mode 100644 index 000000000..365a74e5f --- /dev/null +++ b/config/benchmark_examples/classification-imagenet1k-resnet50/model.yaml @@ -0,0 +1,44 @@ +model: + task: classification + name: resnet50 + checkpoint: + use_pretrained: True + load_head: False + path: ~ + fx_model_path: ~ + optimizer_path: ~ + freeze_backbone: False + architecture: + full: ~ # auto + backbone: + name: resnet + params: + block_type: bottleneck + norm_type: batch_norm + stage_params: + - + channels: 64 + num_blocks: 3 + - + channels: 128 + num_blocks: 4 + replace_stride_with_dilation: False + - + channels: 256 + num_blocks: 6 + replace_stride_with_dilation: False + - + channels: 512 + num_blocks: 3 + replace_stride_with_dilation: False + head: + name: fc + params: + num_layers: 1 + intermediate_channels: ~ + act_type: ~ + dropout_prob: 0. + losses: + - criterion: cross_entropy + label_smoothing: 0.1 + weight: ~ \ No newline at end of file diff --git a/config/benchmark_examples/classification-imagenet1k-resnet50/training.yaml b/config/benchmark_examples/classification-imagenet1k-resnet50/training.yaml new file mode 100644 index 000000000..276b70191 --- /dev/null +++ b/config/benchmark_examples/classification-imagenet1k-resnet50/training.yaml @@ -0,0 +1,15 @@ +training: + epochs: 600 + mixed_precision: False + ema: ~ + optimizer: + name: sgd + lr: 0.5 + momentum: 0.9 + weight_decay: 2e-5 + scheduler: + name: cosine_no_sgdr + warmup_epochs: 5 + warmup_bias_lr: 1e-5 + min_lr: 0. + end_epoch: 600 diff --git a/config/benchmark_examples/detection-coco2017-yolox_s/augmentation.yaml b/config/benchmark_examples/detection-coco2017-yolox_s/augmentation.yaml new file mode 100644 index 000000000..e3a83170d --- /dev/null +++ b/config/benchmark_examples/detection-coco2017-yolox_s/augmentation.yaml @@ -0,0 +1,50 @@ +augmentation: + train: + - + name: mosaicdetection + size: [640, 640] + mosaic_prob: 1.0 + affine_scale: [0.5, 1.5] + degrees: 10.0 + translate: 0.1 + shear: 2.0 + enable_mixup: True + mixup_prob: 1.0 + mixup_scale: [0.1, 2.0] + fill: 144 + mosaic_off_epoch: 285 + - + name: hsvjitter + h_mag: 5 + s_mag: 30 + v_mag: 30 + - + name: randomhorizontalflip + p: 0.5 + - + name: resize + size: 640 + interpolation: bilinear + max_size: ~ + resize_criteria: long + - + name: pad + size: 640 + fill: 114 + - + name: randomresize + base_size: [640, 640] + stride: 32 + random_range: 5 + interpolation: bilinear + inference: + - + name: resize + size: 64 + interpolation: bilinear + max_size: ~ + resize_criteria: long + - + name: pad + size: 640 + fill: 144 diff --git a/config/benchmark_examples/detection-coco2017-yolox_s/data.yaml b/config/benchmark_examples/detection-coco2017-yolox_s/data.yaml new file mode 100644 index 000000000..86801f45a --- /dev/null +++ b/config/benchmark_examples/detection-coco2017-yolox_s/data.yaml @@ -0,0 +1,21 @@ +data: + name: coco2017 + task: detection + format: local # local, huggingface + path: + root: ./data/coco2017 # dataset root + train: + image: images/train # directory for training images + label: labels/train # directory for training labels + valid: + image: images/valid # directory for valid images + label: labels/valid # directory for valid labels + test: + image: ~ + label: ~ + pattern: + image: ~ + label: ~ + id_mapping: id_mapping.json + # id_mapping: ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'] + pallete: ~ diff --git a/config/benchmark_examples/detection-coco2017-yolox_s/environment.yaml b/config/benchmark_examples/detection-coco2017-yolox_s/environment.yaml new file mode 100644 index 000000000..0fbbbf577 --- /dev/null +++ b/config/benchmark_examples/detection-coco2017-yolox_s/environment.yaml @@ -0,0 +1,5 @@ +environment: + seed: 1 + num_workers: 4 + gpus: 0, 1, 2, 3, 4, 5, 6, 7 + batch_size: 8 # Batch size per gpu \ No newline at end of file diff --git a/config/benchmark_examples/detection-coco2017-yolox_s/logging.yaml b/config/benchmark_examples/detection-coco2017-yolox_s/logging.yaml new file mode 100644 index 000000000..7d969aad0 --- /dev/null +++ b/config/benchmark_examples/detection-coco2017-yolox_s/logging.yaml @@ -0,0 +1,10 @@ +logging: + project_id: ~ + output_dir: ./outputs + tensorboard: true + image: true + stdout: true + save_optimizer_state: true + onnx_input_size: [640, 640] + validation_epoch: &validation_epoch 10 + save_checkpoint_epoch: *validation_epoch # Multiplier of `validation_epoch`. \ No newline at end of file diff --git a/config/benchmark_examples/detection-coco2017-yolox_s/model.yaml b/config/benchmark_examples/detection-coco2017-yolox_s/model.yaml new file mode 100644 index 000000000..1b15896e5 --- /dev/null +++ b/config/benchmark_examples/detection-coco2017-yolox_s/model.yaml @@ -0,0 +1,37 @@ +model: + task: detection + name: yolox_s + checkpoint: + use_pretrained: False + load_head: False + path: ~ + fx_model_path: ~ + optimizer_path: ~ + freeze_backbone: False + architecture: + full: ~ # auto + backbone: + name: cspdarknet + params: + dep_mul: &dep_mul 0.33 + wid_mul: 0.5 + act_type: &act_type "silu" + stage_params: ~ + neck: + name: yolopafpn + params: + dep_mul: *dep_mul + act_type: *act_type + head: + name: anchor_free_decoupled_head + params: + act_type: *act_type + # postprocessor - decode + score_thresh: 0.01 + # postprocessor - nms + nms_thresh: 0.65 + class_agnostic: False + losses: + - criterion: yolox_loss + weight: ~ + l1_activate_epoch: 285 \ No newline at end of file diff --git a/config/benchmark_examples/detection-coco2017-yolox_s/training.yaml b/config/benchmark_examples/detection-coco2017-yolox_s/training.yaml new file mode 100644 index 000000000..383c39fb2 --- /dev/null +++ b/config/benchmark_examples/detection-coco2017-yolox_s/training.yaml @@ -0,0 +1,18 @@ +training: + epochs: 300 + mixed_precision: True + ema: + name: exp_decay + decay: 0.9999 + beta: 2000 + optimizer: + name: sgd + lr: 0.01 + momentum: 0.9 + wegight_decay: 0.0005 # No bias and norm decay + scheduler: + name: cosine_no_sgdr + warmup_epochs: 5 + warmup_bias_lr: 0. + min_lr: 0.0005 + end_epoch: 285 diff --git a/config/training.yaml b/config/training.yaml index f250fae16..2eecc8e75 100644 --- a/config/training.yaml +++ b/config/training.yaml @@ -1,5 +1,6 @@ training: epochs: 30 + mixed_precision: False ema: ~ optimizer: name: adamw From 9282e5c61705d23720ce8dfb4dc4ca58d5db7ece Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Thu, 2 May 2024 15:38:47 +0000 Subject: [PATCH 86/91] Fix missed fields --- .../classification-imagenet1k-resnet18/training.yaml | 3 ++- .../classification-imagenet1k-resnet34/training.yaml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/config/benchmark_examples/classification-imagenet1k-resnet18/training.yaml b/config/benchmark_examples/classification-imagenet1k-resnet18/training.yaml index 769a07b37..e7ba53d10 100644 --- a/config/benchmark_examples/classification-imagenet1k-resnet18/training.yaml +++ b/config/benchmark_examples/classification-imagenet1k-resnet18/training.yaml @@ -10,5 +10,6 @@ training: nesterov: False scheduler: name: step - ites_per_phase: 30 + iters_per_phase: 30 gamma: 0.1 + end_epoch: 90 diff --git a/config/benchmark_examples/classification-imagenet1k-resnet34/training.yaml b/config/benchmark_examples/classification-imagenet1k-resnet34/training.yaml index 769a07b37..e7ba53d10 100644 --- a/config/benchmark_examples/classification-imagenet1k-resnet34/training.yaml +++ b/config/benchmark_examples/classification-imagenet1k-resnet34/training.yaml @@ -10,5 +10,6 @@ training: nesterov: False scheduler: name: step - ites_per_phase: 30 + iters_per_phase: 30 gamma: 0.1 + end_epoch: 90 From 63a44a4bc767641cbbaa42f04100b920b65df8b1 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Thu, 2 May 2024 15:41:15 +0000 Subject: [PATCH 87/91] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ce72a8b6..d371bd4c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ No changes to highlight. - Save training summary at every end of epochs by `@illian01` in [PR 420](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/420) - Refacotring: rename postprocessors/register.py to registry.py by `@aychun` in [PR 424](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/424) +- Add example configuration set by `@illian01` in [PR 438](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/438) # v0.2.0 From 0a496d635a7c0e5980ecf00887c62bfc0f707436 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Fri, 3 May 2024 01:08:22 +0000 Subject: [PATCH 88/91] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1920279a0..9271ef47f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ No changes to highlight. - Save training summary at every end of epochs by `@illian01` in [PR 420](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/420) - Refacotring: rename postprocessors/register.py to registry.py by `@aychun` in [PR 424](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/424) +- Documentation: fix simple use config file path by `@cbpark-nota` in [PR 437](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/437) # v0.2.0 From 4c2dd56cdce1cc0f53830fb49ceb4c6a6f932401 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Fri, 3 May 2024 01:19:53 +0000 Subject: [PATCH 89/91] Update pr template --- .github/PULL_REQUEST_TEMPLATE.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index becf5c7b8..866520cd2 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -23,4 +23,6 @@ For example, ``` - Added a new feature by `@myusername` in [PR 2023](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/2023) -``` \ No newline at end of file +``` + +Please enable **Allow edits and access to secrets by maintainers** so that our maintainers can update the `CHANGELOG.md`. \ No newline at end of file From 51e556447ce491933d065ccabae24083b5a0be86 Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Fri, 3 May 2024 01:43:27 +0000 Subject: [PATCH 90/91] Minor typos and print --- .../classification-imagenet1k-resnet34/environment.yaml | 2 +- .../classification-imagenet1k-resnet50/augmentation.yaml | 7 ++++++- .../classification-imagenet1k-resnet50/training.yaml | 1 + .../detection-coco2017-yolox_s/training.yaml | 3 ++- src/netspresso_trainer/pipelines/task_processors/base.py | 1 + 5 files changed, 11 insertions(+), 3 deletions(-) diff --git a/config/benchmark_examples/classification-imagenet1k-resnet34/environment.yaml b/config/benchmark_examples/classification-imagenet1k-resnet34/environment.yaml index fa4d45a21..a24602d60 100644 --- a/config/benchmark_examples/classification-imagenet1k-resnet34/environment.yaml +++ b/config/benchmark_examples/classification-imagenet1k-resnet34/environment.yaml @@ -2,4 +2,4 @@ environment: seed: 1 num_workers: 4 gpus: 0, 1, 2, 3, 4, 5, 6, 7 - batch_size: 23 # Batch size per gpu \ No newline at end of file + batch_size: 32 # Batch size per gpu \ No newline at end of file diff --git a/config/benchmark_examples/classification-imagenet1k-resnet50/augmentation.yaml b/config/benchmark_examples/classification-imagenet1k-resnet50/augmentation.yaml index 6f9d0ed1a..2be4d662b 100644 --- a/config/benchmark_examples/classification-imagenet1k-resnet50/augmentation.yaml +++ b/config/benchmark_examples/classification-imagenet1k-resnet50/augmentation.yaml @@ -13,9 +13,14 @@ augmentation: name: trivialaugmentwide num_magnitude_bins: 31 interpolation: 'bilinear' + fill: ~ - name: randomerasing p: 0.1 + scale: [0.02, 0.33] + ratio: [0.3, 3.3] + value: 0 + inplace: False - name: mixing mixup: [0.2, 1.0] @@ -24,7 +29,7 @@ augmentation: inference: - name: resize - size: [256, 256] + size: [232, 232] interpolation: bilinear max_size: ~ resize_criteria: ~ diff --git a/config/benchmark_examples/classification-imagenet1k-resnet50/training.yaml b/config/benchmark_examples/classification-imagenet1k-resnet50/training.yaml index 276b70191..3b00d7838 100644 --- a/config/benchmark_examples/classification-imagenet1k-resnet50/training.yaml +++ b/config/benchmark_examples/classification-imagenet1k-resnet50/training.yaml @@ -7,6 +7,7 @@ training: lr: 0.5 momentum: 0.9 weight_decay: 2e-5 + nesterov: False scheduler: name: cosine_no_sgdr warmup_epochs: 5 diff --git a/config/benchmark_examples/detection-coco2017-yolox_s/training.yaml b/config/benchmark_examples/detection-coco2017-yolox_s/training.yaml index 383c39fb2..825d50548 100644 --- a/config/benchmark_examples/detection-coco2017-yolox_s/training.yaml +++ b/config/benchmark_examples/detection-coco2017-yolox_s/training.yaml @@ -9,7 +9,8 @@ training: name: sgd lr: 0.01 momentum: 0.9 - wegight_decay: 0.0005 # No bias and norm decay + weight_decay: 0.0005 # No bias and norm decay + nesterov: True scheduler: name: cosine_no_sgdr warmup_epochs: 5 diff --git a/src/netspresso_trainer/pipelines/task_processors/base.py b/src/netspresso_trainer/pipelines/task_processors/base.py index f410397f6..ef05e4405 100644 --- a/src/netspresso_trainer/pipelines/task_processors/base.py +++ b/src/netspresso_trainer/pipelines/task_processors/base.py @@ -23,6 +23,7 @@ def __init__(self, conf, postprocessor, devices, **kwargs): self.mixed_precision = False if self.mixed_precision: if self.single_gpu_or_rank_zero: + logger.info("-" * 40) logger.info("Mixed precision training activated.") self.data_type = torch.float16 else: From 86880fec5bd3255a4497d9a8feb0b898e794c9fe Mon Sep 17 00:00:00 2001 From: "junho.shin" Date: Fri, 3 May 2024 02:19:58 +0000 Subject: [PATCH 91/91] v0.2.1 release commit --- CHANGELOG.md | 18 ++++++++++++++++++ src/netspresso_trainer/VERSION | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee595f5fa..473879c58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,24 @@ ## New Features: +No changes to highlight. + +## Bug Fixes: + +No changes to highlight. + +## Breaking Changes: + +No changes to highlight. + +## Other Changes: + +No changes to highlight. + +# v0.2.1 + +## New Features: + - Add dataset validation step and refactoring data modules by `@illian01` in [PR 417](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/417), [PR 419](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/419) - Add various dataset examples including automatic open dataset format converter by `@illian01` in [PR 430](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/430) - Allow using text file path for the `id_mapping` field by `@illian01` in [PR 432](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/432), [PR 435](https://github.com/Nota-NetsPresso/netspresso-trainer/pull/435) diff --git a/src/netspresso_trainer/VERSION b/src/netspresso_trainer/VERSION index 341cf11fa..7dff5b892 100644 --- a/src/netspresso_trainer/VERSION +++ b/src/netspresso_trainer/VERSION @@ -1 +1 @@ -0.2.0 \ No newline at end of file +0.2.1 \ No newline at end of file