|
@@ -20,12 +20,6 @@ from chainer_addons.functions import smoothed_cross_entropy
|
|
from cvdatasets.annotations import AnnotationType
|
|
from cvdatasets.annotations import AnnotationType
|
|
from cvdatasets.utils import new_iterator
|
|
from cvdatasets.utils import new_iterator
|
|
|
|
|
|
-from finetune.core.classifier import FVEMixin
|
|
|
|
-from finetune.core.classifier import BasePartsClassifier
|
|
|
|
-from finetune.core.training import AlphaPoolingTrainer
|
|
|
|
-from finetune.core.training import Trainer
|
|
|
|
-from finetune.core.dataset import Dataset
|
|
|
|
-
|
|
|
|
from functools import partial
|
|
from functools import partial
|
|
from os.path import join
|
|
from os.path import join
|
|
|
|
|
|
@@ -36,15 +30,19 @@ def check_param_for_decay(param):
|
|
return param.name != "alpha"
|
|
return param.name != "alpha"
|
|
|
|
|
|
|
|
|
|
|
|
+def _format_kwargs(kwargs):
|
|
|
|
+ return " ".join([f"{key}={value}" for key, value in kwargs.items()])
|
|
|
|
+
|
|
class _ModelMixin(abc.ABC):
|
|
class _ModelMixin(abc.ABC):
|
|
"""This mixin is responsible for optimizer creation, model creation,
|
|
"""This mixin is responsible for optimizer creation, model creation,
|
|
model wrapping around a classifier and model weights loading.
|
|
model wrapping around a classifier and model weights loading.
|
|
"""
|
|
"""
|
|
|
|
|
|
- def __init__(self, classifier_cls, classifier_kwargs, *args, **kwargs):
|
|
|
|
|
|
+ def __init__(self, classifier_cls, classifier_kwargs={}, model_kwargs={}, *args, **kwargs):
|
|
super(_ModelMixin, self).__init__(*args, **kwargs)
|
|
super(_ModelMixin, self).__init__(*args, **kwargs)
|
|
- self.classifier_kwargs = classifier_kwargs
|
|
|
|
self.classifier_cls = classifier_cls
|
|
self.classifier_cls = classifier_cls
|
|
|
|
+ self.classifier_kwargs = classifier_kwargs
|
|
|
|
+ self.model_kwargs = model_kwargs
|
|
|
|
|
|
def wrap_model(self, opts):
|
|
def wrap_model(self, opts):
|
|
|
|
|
|
@@ -55,10 +53,9 @@ class _ModelMixin(abc.ABC):
|
|
loss_func=self._loss_func(opts),
|
|
loss_func=self._loss_func(opts),
|
|
**kwargs)
|
|
**kwargs)
|
|
|
|
|
|
- kwargs_info = " ".join([f"{key}={value}" for key, value in kwargs.items()])
|
|
|
|
logging.info(" ".join([
|
|
logging.info(" ".join([
|
|
f"Wrapped the model around {clf_class.__name__}",
|
|
f"Wrapped the model around {clf_class.__name__}",
|
|
- f"with kwargs: {kwargs_info}",
|
|
|
|
|
|
+ f"with kwargs: {_format_kwargs(kwargs)}",
|
|
]))
|
|
]))
|
|
|
|
|
|
def _loss_func(self, opts):
|
|
def _loss_func(self, opts):
|
|
@@ -115,12 +112,13 @@ class _ModelMixin(abc.ABC):
|
|
self.model = ModelType.new(
|
|
self.model = ModelType.new(
|
|
model_type=self.model_info.class_key,
|
|
model_type=self.model_info.class_key,
|
|
input_size=opts.input_size,
|
|
input_size=opts.input_size,
|
|
- pooling=opts.pooling,
|
|
|
|
- pooling_params=dict(
|
|
|
|
- init_alpha=opts.init_alpha,
|
|
|
|
- output_dim=8192,
|
|
|
|
- normalize=opts.normalize),
|
|
|
|
- aux_logits=False
|
|
|
|
|
|
+ **self.model_kwargs,
|
|
|
|
+ # pooling=opts.pooling,
|
|
|
|
+ # pooling_params=dict(
|
|
|
|
+ # init_alpha=opts.init_alpha,
|
|
|
|
+ # output_dim=8192,
|
|
|
|
+ # normalize=opts.normalize),
|
|
|
|
+ # aux_logits=False
|
|
)
|
|
)
|
|
|
|
|
|
def load_model_weights(self, args):
|
|
def load_model_weights(self, args):
|
|
@@ -144,14 +142,7 @@ class _ModelMixin(abc.ABC):
|
|
loader = partial(self.model.load_for_finetune, weights=self.weights)
|
|
loader = partial(self.model.load_for_finetune, weights=self.weights)
|
|
|
|
|
|
|
|
|
|
- if hasattr(self.model.pool, "output_dim") and self.model.pool.output_dim is not None:
|
|
|
|
- feat_size = self.model.pool.output_dim
|
|
|
|
-
|
|
|
|
- elif isinstance(self.clf, (BasePartsClassifier, FVEMixin)):
|
|
|
|
- feat_size = self.clf.outsize
|
|
|
|
-
|
|
|
|
- else:
|
|
|
|
- feat_size = self.model.meta.feature_size
|
|
|
|
|
|
+ feat_size = self.clf.feat_size
|
|
|
|
|
|
if hasattr(self.clf, "loader"):
|
|
if hasattr(self.clf, "loader"):
|
|
loader = self.clf.loader(loader)
|
|
loader = self.clf.loader(loader)
|
|
@@ -180,10 +171,11 @@ class _DatasetMixin(abc.ABC):
|
|
subset=subset,
|
|
subset=subset,
|
|
dataset_cls=self.dataset_cls,
|
|
dataset_cls=self.dataset_cls,
|
|
)
|
|
)
|
|
- if opts.use_parts:
|
|
|
|
- kwargs.update(dict(
|
|
|
|
- no_glob=opts.no_global,
|
|
|
|
- ))
|
|
|
|
|
|
+
|
|
|
|
+ # if opts.use_parts:
|
|
|
|
+ # kwargs.update(dict(
|
|
|
|
+ # no_glob=opts.no_global,
|
|
|
|
+ # ))
|
|
|
|
|
|
if not opts.only_head:
|
|
if not opts.only_head:
|
|
kwargs.update(dict(
|
|
kwargs.update(dict(
|
|
@@ -192,13 +184,12 @@ class _DatasetMixin(abc.ABC):
|
|
size=size,
|
|
size=size,
|
|
center_crop_on_val=not opts.no_center_crop_on_val,
|
|
center_crop_on_val=not opts.no_center_crop_on_val,
|
|
|
|
|
|
- # return_part_crops=args.use_parts,
|
|
|
|
))
|
|
))
|
|
|
|
|
|
d = self.annot.new_dataset(**kwargs)
|
|
d = self.annot.new_dataset(**kwargs)
|
|
logging.info("Loaded {} images".format(len(d)))
|
|
logging.info("Loaded {} images".format(len(d)))
|
|
logging.info("Data augmentation is {}abled".format("en" if augment else "dis"))
|
|
logging.info("Data augmentation is {}abled".format("en" if augment else "dis"))
|
|
- logging.info("Global feature is {}used".format("not " if opts.no_global else ""))
|
|
|
|
|
|
+ # logging.info("Global feature is {}used".format("not " if opts.no_global else ""))
|
|
return d
|
|
return d
|
|
|
|
|
|
def init_annotations(self, opts):
|
|
def init_annotations(self, opts):
|
|
@@ -218,7 +209,7 @@ class _DatasetMixin(abc.ABC):
|
|
|
|
|
|
self.dataset_cls.label_shift = opts.label_shift
|
|
self.dataset_cls.label_shift = opts.label_shift
|
|
|
|
|
|
- size = 112 if opts.recurrent else self.model.meta.input_size
|
|
|
|
|
|
+ size = self.model.meta.input_size
|
|
|
|
|
|
self.prepare = partial(PrepareType[opts.prepare_type](self.model),
|
|
self.prepare = partial(PrepareType[opts.prepare_type](self.model),
|
|
swap_channels=opts.swap_channels,
|
|
swap_channels=opts.swap_channels,
|
|
@@ -251,16 +242,25 @@ class _TrainerMixin(abc.ABC):
|
|
Furthermore, it implements the run method
|
|
Furthermore, it implements the run method
|
|
"""
|
|
"""
|
|
|
|
|
|
- def init_updater(self, updater_cls=StandardUpdater, updater_kwargs={}):
|
|
|
|
- """Creates an updater from training iterator and the optimizer."""
|
|
|
|
|
|
+ def __init__(self, updater_cls, updater_kwargs={}, *args, **kwargs):
|
|
|
|
+ super(_TrainerMixin, self).__init__(*args, **kwargs)
|
|
|
|
+ self.updater_cls = updater_cls
|
|
|
|
+ self.updater_kwargs = updater_kwargs
|
|
|
|
|
|
- self.updater = updater_cls(
|
|
|
|
|
|
+ def init_updater(self):
|
|
|
|
+ """Creates an updater from training iterator and the optimizer."""
|
|
|
|
+ self.updater = self.updater_cls(
|
|
iterator=self.train_iter,
|
|
iterator=self.train_iter,
|
|
optimizer=self.opt,
|
|
optimizer=self.opt,
|
|
device=self.device,
|
|
device=self.device,
|
|
- **updater_kwargs,
|
|
|
|
|
|
+ **self.updater_kwargs,
|
|
|
|
+ )
|
|
|
|
+ logging.info(" ".join([
|
|
|
|
+ f"Using single GPU: {self.device}."
|
|
|
|
+ f"{self.updater_cls.__name__} is initialized",
|
|
|
|
+ f"with following kwargs: {_format_kwargs(self.updater_kwargs)}"
|
|
|
|
+ ])
|
|
)
|
|
)
|
|
- logging.info(f"Using single GPU: {self.device}. {updater_cls.__name__} is initialized.")
|
|
|
|
|
|
|
|
def init_evaluator(self, default_name="val"):
|
|
def init_evaluator(self, default_name="val"):
|
|
"""Creates evaluation extension from validation iterator and the classifier."""
|
|
"""Creates evaluation extension from validation iterator and the classifier."""
|
|
@@ -272,16 +272,14 @@ class _TrainerMixin(abc.ABC):
|
|
|
|
|
|
self.evaluator.default_name = default_name
|
|
self.evaluator.default_name = default_name
|
|
|
|
|
|
- def run(self, opts, ex, no_observe=False):
|
|
|
|
|
|
+ def run(self, trainer_cls, opts, *args, **kwargs):
|
|
|
|
|
|
- trainer_cls = AlphaPoolingTrainer if opts.pooling=="alpha" else Trainer
|
|
|
|
trainer = trainer_cls(
|
|
trainer = trainer_cls(
|
|
- ex=ex,
|
|
|
|
opts=opts,
|
|
opts=opts,
|
|
updater=self.updater,
|
|
updater=self.updater,
|
|
evaluator=self.evaluator,
|
|
evaluator=self.evaluator,
|
|
weights=self.weights,
|
|
weights=self.weights,
|
|
- no_observe=no_observe
|
|
|
|
|
|
+ *args, **kwargs
|
|
)
|
|
)
|
|
def dump(suffix):
|
|
def dump(suffix):
|
|
if opts.only_eval or opts.no_snapshot:
|
|
if opts.only_eval or opts.no_snapshot:
|
|
@@ -309,21 +307,11 @@ class DefaultFinetuner(_ModelMixin, _DatasetMixin, _TrainerMixin):
|
|
|
|
|
|
"""
|
|
"""
|
|
|
|
|
|
-
|
|
|
|
def __init__(self, opts, *args, **kwargs):
|
|
def __init__(self, opts, *args, **kwargs):
|
|
- super(BaseFinetuner, self).__init__()
|
|
|
|
|
|
+ super(DefaultFinetuner, self).__init__(*args, **kwargs)
|
|
|
|
|
|
self.gpu_config(opts, *args, **kwargs)
|
|
self.gpu_config(opts, *args, **kwargs)
|
|
|
|
|
|
- def gpu_config(self, opts):
|
|
|
|
- if -1 in opts.gpu:
|
|
|
|
- self.device = -1
|
|
|
|
- else:
|
|
|
|
- self.device = opts.gpu[0]
|
|
|
|
- cuda.get_device_from_id(self.device).use()
|
|
|
|
-
|
|
|
|
- def setup(self, opts, updater_cls, updater_kwargs):
|
|
|
|
-
|
|
|
|
self.init_annotations(opts)
|
|
self.init_annotations(opts)
|
|
self.init_model(opts)
|
|
self.init_model(opts)
|
|
|
|
|
|
@@ -334,6 +322,13 @@ class DefaultFinetuner(_ModelMixin, _DatasetMixin, _TrainerMixin):
|
|
self.load_model_weights(opts)
|
|
self.load_model_weights(opts)
|
|
|
|
|
|
self.init_optimizer(opts)
|
|
self.init_optimizer(opts)
|
|
- self.init_updater(updater_cls=updater_cls, updater_kwargs=updater_kwargs)
|
|
|
|
|
|
+ self.init_updater()
|
|
self.init_evaluator()
|
|
self.init_evaluator()
|
|
|
|
|
|
|
|
+ def gpu_config(self, opts, *args, **kwargs):
|
|
|
|
+ if -1 in opts.gpu:
|
|
|
|
+ self.device = -1
|
|
|
|
+ else:
|
|
|
|
+ self.device = opts.gpu[0]
|
|
|
|
+ cuda.get_device_from_id(self.device).use()
|
|
|
|
+
|