Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
tkianai committed Apr 27, 2020
1 parent fe9905b commit 8c68af9
Show file tree
Hide file tree
Showing 21 changed files with 1,599 additions and 0 deletions.
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!--
* @Copyright (c) tkianai All Rights Reserved.
* @Author : tkianai
* @Github : https://github.com/tkianai
* @Date : 2020-04-26 13:58:01
* @FilePath : /ImageCls.detectron2/README.md
* @Description :
-->


# ImageClassification.detectron2

Image classification based on detectron2.

This provides a convenient way to initialize backbone in detectron2.


## Usage

- Trained with detectron2 builtin trainer

1. Use default data flow in detectron2, you only need rename `forward_d2` to `forward`, while renaming `forward` to `forward_imgnet` in `imgcls/modeling/meta_arch/clsnet.py`

2. Create your own model config

3. Run: `python train_net_builtin.py --num-gpus <gpu number> --config-file configs/<your config file>`. For example: `sh scripts/train_net_builtin.sh`


- Trained with pytorch formal imagenet trainer

1. Read carefully with some arguments in `train_net.py`
2. Run: `sh /scripts/train_net.sh`
28 changes: 28 additions & 0 deletions configs/Base_image_cls.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
MODEL:
META_ARCHITECTURE: "ClsNet"
BACKBONE:
NAME: "build_mnetv1_backbone"
FREEZE_AT: 0
MNET:
OUT_FEATURES: ['linear']
WIDTH_MULT: 0.25
CLSNET:
ENABLE: True
NUM_CLASSES: 1000
INPUT_SIZE: 224

DATASETS:
TRAIN: ("imagenet_train", )
TEST: ("imagenet_val", )
DATALOADER:
ASPECT_RATIO_GROUPING: False
NUM_WORKERS: 4
SOLVER:
IMS_PER_BATCH: 512
BASE_LR: 0.1
STEPS: (150000, 180000)
MAX_ITER: 200000
INPUT:
CROP:
ENABLED: True
VERSION: 2
10 changes: 10 additions & 0 deletions imgcls/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'''
@Copyright (c) tkianai All Rights Reserved.
@Author : tkianai
@Github : https://github.com/tkianai
@Date : 2020-04-26 14:00:17
@FilePath : /ImageCls.detectron2/imgcls/__init__.py
@Description :
'''


26 changes: 26 additions & 0 deletions imgcls/config/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'''
@Copyright (c) tkianai All Rights Reserved.
@Author : tkianai
@Github : https://github.com/tkianai
@Date : 2020-04-26 14:18:06
@FilePath : /ImageCls.detectron2/imgcls/config/__init__.py
@Description :
'''

from detectron2.config import CfgNode


__all__ = ['get_cfg']


def get_cfg() -> CfgNode:
"""Get a copy of the default config
Returns:
CfgNode -- a detectron2 CfgNode instance
"""

from .defaults import _C
return _C.clone()


36 changes: 36 additions & 0 deletions imgcls/config/defaults.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
'''
@Copyright (c) tkianai All Rights Reserved.
@Author : tkianai
@Github : https://github.com/tkianai
@Date : 2020-04-26 14:26:03
@FilePath : /ImageCls.detectron2/imgcls/config/defaults.py
@Description :
'''


from detectron2.config.defaults import _C
from detectron2.config import CfgNode as CN


# ---------------------------------------------------------------------------- #
# MobileNets
# ---------------------------------------------------------------------------- #
_C.MODEL.MNET = CN()

# Output features
_C.MODEL.MNET.OUT_FEATURES = ['linear']
# Width mult
_C.MODEL.MNET.WIDTH_MULT = 1.0


# ---------------------------------------------------------------------------- #
# ClsNets
# ---------------------------------------------------------------------------- #
_C.MODEL.CLSNET = CN()
_C.MODEL.CLSNET.ENABLE = False
# classes number
_C.MODEL.CLSNET.NUM_CLASSES = 1000
# In features
_C.MODEL.CLSNET.IN_FEATURES = ['linear']
# Input Size
_C.MODEL.CLSNET.INPUT_SIZE = 224
12 changes: 12 additions & 0 deletions imgcls/data/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
'''
@Copyright (c) tkianai All Rights Reserved.
@Author : tkianai
@Github : https://github.com/tkianai
@Date : 2020-04-26 16:40:05
@FilePath : /ImageCls.detectron2/imgcls/data/__init__.py
@Description :
'''


from .imagenet import register_imagenet_instances
from .dataset_mapper import DatasetMapper
35 changes: 35 additions & 0 deletions imgcls/data/classification_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
'''
@Copyright (c) tkianai All Rights Reserved.
@Author : tkianai
@Github : https://github.com/tkianai
@Date : 2020-04-26 17:01:36
@FilePath : /ImageCls.detectron2/imgcls/data/classification_utils.py
@Description :
'''


import detectron2.data.transforms as T
import logging


def build_transform_gen(cfg, is_train):
"""
Create a list of :class:`TransformGen` from config.
Now it includes resizing and flipping.
Returns:
list[TransformGen]
"""
input_size = cfg.MODEL.CLSNET.INPUT_SIZE

logger = logging.getLogger("detectron2.data.classification_utils")
tfm_gens = []
tfm_gens.append(T.Resize((input_size, input_size)))
if is_train:
tfm_gens.append(T.RandomContrast(0.5, 1.5))
tfm_gens.append(T.RandomBrightness(0.5, 1.5))
tfm_gens.append(T.RandomSaturation(0.5, 1.5))
tfm_gens.append(T.RandomFlip())
logger.info(
"TransformGens used in training[Updated]: " + str(tfm_gens))
return tfm_gens
22 changes: 22 additions & 0 deletions imgcls/data/dataset_mapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'''
@Copyright (c) tkianai All Rights Reserved.
@Author : tkianai
@Github : https://github.com/tkianai
@Date : 2020-04-26 17:01:20
@FilePath : /ImageCls.detectron2/imgcls/data/dataset_mapper.py
@Description :
'''

from . import classification_utils as c_utils


from detectron2.data.dataset_mapper import DatasetMapper as _DatasetMapper



class DatasetMapper(_DatasetMapper):

def __init__(self, cfg, is_train=True):
super().__init__(cfg, is_train)

self.tfm_gens = c_utils.build_transform_gen(cfg, is_train)
41 changes: 41 additions & 0 deletions imgcls/data/imagenet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'''
@Copyright (c) tkianai All Rights Reserved.
@Author : tkianai
@Github : https://github.com/tkianai
@Date : 2020-04-26 17:02:07
@FilePath : /ImageCls.detectron2/imgcls/data/imagenet.py
@Description :
'''


import os
import os.path as osp
import json
from detectron2.data import DatasetCatalog, MetadataCatalog


def register_imagenet_instances(name, metadata, json_file):

assert isinstance(name, str), name
assert isinstance(json_file, (str, os.PathLike)), json_file

# 1. register a function which returns dicts
DatasetCatalog.register(name, lambda: json.load(open(json_file)))

# 2. Optionally, add metadata about this dataset,
# since they might be useful in evaluation, visualization or logging
MetadataCatalog.get(name).set(
json_file=json_file, evaluator_type="imagenet", **metadata
)


# Update info
_root = os.getenv("DETECTRON2_DATASETS", "datasets")
imagenet_train_annotation_file = osp.join(_root, "ImageNet2012/imagenet_detectron2_train.json")
imagenet_val_annotation_file = osp.join(_root, "ImageNet2012/imagenet_detectron2_val.json")

# Register into DatasetCatalog
register_imagenet_instances("imagenet_train", {}, imagenet_train_annotation_file)
register_imagenet_instances("imagenet_val", {}, imagenet_val_annotation_file)


11 changes: 11 additions & 0 deletions imgcls/evaluation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
'''
@Copyright (c) tkianai All Rights Reserved.
@Author : tkianai
@Github : https://github.com/tkianai
@Date : 2020-04-26 19:41:56
@FilePath : /ImageCls.detectron2/imgcls/evaluation/__init__.py
@Description :
'''


from .imagenet_evaluation import ImageNetEvaluator
84 changes: 84 additions & 0 deletions imgcls/evaluation/imagenet_evaluation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
'''
@Copyright (c) tkianai All Rights Reserved.
@Author : tkianai
@Github : https://github.com/tkianai
@Date : 2020-04-26 19:42:05
@FilePath : /ImageCls.detectron2/imgcls/evaluation/imagenet_evaluation.py
@Description :
'''


import itertools
import json
import logging
from collections import OrderedDict
import torch
from fvcore.common.file_io import PathManager

import detectron2.utils.comm as comm
from detectron2.data import MetadataCatalog
from detectron2.evaluation.evaluator import DatasetEvaluator


class ImageNetEvaluator(DatasetEvaluator):

def __init__(self, dataset_name, cfg, distributed, output_dir=None):
self._distributed = distributed
self._output_dir = output_dir

self._cpu_device = torch.device("cpu")
self._logger = logging.getLogger("detectron2.evaluation.imagenet_evaluation")

self._metadata = MetadataCatalog.get(dataset_name)

json_file = PathManager.get_local_path(self._metadata.json_file)
self._gt = json.load(open(json_file))

def reset(self):
self._predictions = []

def process(self, inputs, outputs):
for input, output in zip(inputs, outputs):
prediction = {"image_id": input["image_id"]}
prediction["gt"] = input["label"]
prediction["pred"] = output["pred_classes"].to(self._cpu_device)
self._predictions.append(prediction)


def evaluate(self):
if self._distributed:
comm.synchronize()
predictions = comm.gather(self._predictions, dst=0)
predictions = list(itertools.chain(*predictions))

if not comm.is_main_process():
return {}
else:
predictions = self._predictions

if len(predictions) == 0:
self._logger.warning(
"[ImageNetEvaluator] Did not receive valid predictions.")
return {}

topk = len(self._predictions[0]['pred'])
target = []
pred = []
for p in self._predictions:
target.append(p['gt'])
pred.append(p['pred'])
pred = torch.stack(pred, dim=0)
target = torch.as_tensor(target, dtype=pred.dtype)
num_samples = target.size(0)

pred = pred.t()
correct = pred.eq(target.view(1, -1).expand_as(pred))

topk_acc = []
for k in range(1, topk + 1):
correct_k = correct[:k].view(-1).float().sum(0, keepdim=True)
topk_acc.append(correct_k.mul_(100.0 / num_samples))
result = OrderedDict(
accuracy={"top{}".format(i + 1): acc.item() for i, acc in enumerate(topk_acc)},
)
return result
15 changes: 15 additions & 0 deletions imgcls/modeling/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'''
@Copyright (c) tkianai All Rights Reserved.
@Author : tkianai
@Github : https://github.com/tkianai
@Date : 2020-04-26 14:11:12
@FilePath : /ImageCls.detectron2/imgcls/modeling/__init__.py
@Description :
'''


from .backbone import *
from .meta_arch import *


__all__ = [k for k in globals().keys() if not k.startswith("_")]
14 changes: 14 additions & 0 deletions imgcls/modeling/backbone/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
'''
@Copyright (c) tkianai All Rights Reserved.
@Author : tkianai
@Github : https://github.com/tkianai
@Date : 2020-04-26 14:11:49
@FilePath : /ImageCls.detectron2/imgcls/modeling/backbone/__init__.py
@Description :
'''


from .mobilenet import *


__all__ = [k for k in globals().keys() if not k.startswith("_")]
Loading

0 comments on commit 8c68af9

Please sign in to comment.