forked from akTwelve/Mask_RCNN
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Changes in model.py and annotations. added attribute annotations
- Loading branch information
Christian
committed
Nov 10, 2020
1 parent
8708258
commit cc776a6
Showing
10 changed files
with
239 additions
and
3,134 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,4 +8,4 @@ tensorflow>=2.0.0 | |
opencv-python | ||
h5py | ||
imgaug | ||
IPython[all] | ||
IPython[all] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,232 @@ | ||
import os | ||
import sys | ||
import json | ||
import numpy as np | ||
import time | ||
from PIL import Image, ImageDraw | ||
|
||
# Set the ROOT_DIR variable to the root directory of the Mask_RCNN git repo | ||
ROOT_DIR = '../../' | ||
assert os.path.exists(ROOT_DIR), 'ROOT_DIR does not exist. Did you forget to read the instructions above? ;)' | ||
|
||
# Import mrcnn libraries | ||
sys.path.append(ROOT_DIR) | ||
from mrcnn.config import Config | ||
import mrcnn.utils as utils | ||
from mrcnn import visualize | ||
import mrcnn.model as modellib | ||
|
||
# Directory to save logs and trained model | ||
MODEL_DIR = "/media/christian/SamsungSSD/tensorflow_logs/" | ||
|
||
# Local path to trained weights file | ||
COCO_MODEL_PATH = os.path.join(ROOT_DIR, "mask_rcnn_coco.h5") | ||
|
||
# Download COCO trained weights from Releases if needed | ||
if not os.path.exists(COCO_MODEL_PATH): | ||
utils.download_trained_weights(COCO_MODEL_PATH) | ||
|
||
class CigButtsConfig(Config): | ||
"""Configuration for training on the cigarette butts dataset. | ||
Derives from the base Config class and overrides values specific | ||
to the cigarette butts dataset. | ||
""" | ||
# Give the configuration a recognizable name | ||
NAME = "feather__damage" | ||
|
||
# Train on 1 GPU and 1 image per GPU. Batch size is 1 (GPUs * images/GPU). | ||
GPU_COUNT = 1 | ||
IMAGES_PER_GPU = 1 | ||
|
||
# Number of classes (including background) | ||
NUM_CLASSES = 1 + 2 # background + 2 (feather damage + no feather damage) | ||
|
||
# All of our training images are 512x512 | ||
IMAGE_MIN_DIM = None | ||
IMAGE_MAX_DIM = 512 # must be dividable by 2 at least 6 times | ||
|
||
# You can experiment with this number to see if it improves training | ||
STEPS_PER_EPOCH = 50 # 500 | ||
|
||
# This is how often validation is run. If you are using too much hard drive space | ||
# on saved models (in the MODEL_DIR), try making this value larger. | ||
VALIDATION_STEPS = 10 # 5 | ||
|
||
# Matterport originally used resnet101, but I downsized to fit it on my graphics card | ||
BACKBONE = 'resnet50' | ||
|
||
# To be honest, I haven't taken the time to figure out what these do | ||
RPN_ANCHOR_SCALES = (8, 16, 32, 64, 128) | ||
TRAIN_ROIS_PER_IMAGE = 32 | ||
MAX_GT_INSTANCES = 20 | ||
POST_NMS_ROIS_INFERENCE = 500 | ||
POST_NMS_ROIS_TRAINING = 1000 | ||
|
||
config = CigButtsConfig() | ||
config.display() | ||
|
||
class CocoLikeDataset(utils.Dataset): | ||
""" Generates a COCO-like dataset, i.e. an image dataset annotated in the style of the COCO dataset. | ||
See http://cocodataset.org/#home for more information. | ||
""" | ||
def load_data(self, annotation_json, images_dir): | ||
""" Load the coco-like dataset from json | ||
Args: | ||
annotation_json: The path to the coco annotations json file | ||
images_dir: The directory holding the images referred to by the json file | ||
""" | ||
# Load json from file | ||
json_file = open(annotation_json) | ||
coco_json = json.load(json_file) | ||
json_file.close() | ||
|
||
# Add the class names using the base method from utils.Dataset | ||
source_name = "coco_like" | ||
for category in coco_json['categories']: | ||
class_id = category['id'] | ||
class_name = category['name'] | ||
if class_id < 1: | ||
print('Error: Class id for "{}" cannot be less than one. (0 is reserved for the background)'.format(class_name)) | ||
return | ||
|
||
self.add_class(source_name, class_id, class_name) | ||
|
||
# Get all annotations | ||
annotations = {} | ||
for annotation in coco_json['annotations']: | ||
image_id = annotation['image_id'] | ||
if image_id not in annotations: | ||
annotations[image_id] = [] | ||
annotations[image_id].append(annotation) | ||
|
||
# Get all images and add them to the dataset | ||
seen_images = {} | ||
for image in coco_json['images']: | ||
image_id = image['id'] | ||
if image_id in seen_images: | ||
print("Warning: Skipping duplicate image id: {}".format(image)) | ||
else: | ||
seen_images[image_id] = image | ||
try: | ||
#image_file_name = format(image['id'], '08d')+"_"+image['file_name'] | ||
image_file_name = image['file_name'] | ||
image_width = image['width'] | ||
image_height = image['height'] | ||
except KeyError as key: | ||
print("Warning: Skipping image (id: {}) with missing key: {}".format(image_id, key)) | ||
|
||
image_path = os.path.abspath(os.path.join(images_dir, image_file_name)) | ||
image_annotations = annotations[image_id] | ||
hasCrowd = False # Quick fix to avoid problems with "count" annotations. If more than 1segmentation/object -> skip image | ||
for element in image_annotations: | ||
if element['iscrowd']: | ||
hasCrowd = True | ||
|
||
# Add the image using the base method from utils.Dataset (if file exists) | ||
if os.path.isfile(image_path): | ||
if not hasCrowd: | ||
self.add_image( | ||
source=source_name, | ||
image_id=image_id, | ||
path=image_path, | ||
width=image_width, | ||
height=image_height, | ||
annotations=image_annotations | ||
) | ||
|
||
|
||
def load_mask(self, image_id): | ||
""" Load instance masks for the given image. | ||
MaskRCNN expects masks in the form of a bitmap [height, width, instances]. | ||
Args: | ||
image_id: The id of the image to load masks for | ||
Returns: | ||
masks: A bool array of shape [height, width, instance count] with | ||
one mask per instance. | ||
class_ids: a 1D array of class IDs of the instance masks. | ||
""" | ||
image_info = self.image_info[image_id] | ||
annotations = image_info['annotations'] | ||
instance_masks = [] | ||
class_ids = [] | ||
|
||
for annotation in annotations: | ||
class_id = annotation['category_id'] | ||
mask = Image.new('1', (image_info['width'], image_info['height'])) | ||
mask_draw = ImageDraw.ImageDraw(mask, '1') | ||
for segmentation in annotation['segmentation']: | ||
mask_draw.polygon(segmentation, fill=1) | ||
bool_array = np.array(mask) > 0 | ||
instance_masks.append(bool_array) | ||
class_ids.append(class_id) | ||
|
||
mask = np.dstack(instance_masks) | ||
class_ids = np.array(class_ids, dtype=np.int32) | ||
|
||
return mask, class_ids | ||
|
||
dataset_train = CocoLikeDataset() | ||
dataset_train.load_data('/media/christian/SamsungSSD/ZED/datasets/900_images/attribute_annotations.json', '/media/christian/SamsungSSD/ZED/datasets/900_images/train/') | ||
dataset_train.prepare() | ||
|
||
dataset_val = CocoLikeDataset() | ||
dataset_val.load_data('/media/christian/SamsungSSD/ZED/datasets/900_images/attribute_annotations.json', '/media/christian/SamsungSSD/ZED/datasets/900_images/val/') | ||
dataset_val.prepare() | ||
|
||
print(dataset_train) | ||
#dataset = dataset_train | ||
#image_ids = np.random.choice(dataset.image_ids, 4) | ||
#for image_id in image_ids: | ||
# image = dataset.load_image(image_id) | ||
# #print(image.shape) | ||
# mask, class_ids = dataset.load_mask(image_id) | ||
# visualize.display_top_masks(image, mask, class_ids, dataset.class_names) | ||
|
||
#### Training #### | ||
|
||
# Create model in training mode | ||
model = modellib.MaskRCNN(mode="training", config=config, | ||
model_dir=MODEL_DIR) | ||
|
||
# Which weights to start with? | ||
init_with = "coco" # imagenet, coco, or last | ||
|
||
if init_with == "imagenet": | ||
model.load_weights(model.get_imagenet_weights(), by_name=True) | ||
elif init_with == "coco": | ||
# Load weights trained on MS COCO, but skip layers that | ||
# are different due to the different number of classes | ||
# See README for instructions to download the COCO weights | ||
model.load_weights(COCO_MODEL_PATH, by_name=True, | ||
exclude=["mrcnn_class_logits", "mrcnn_bbox_fc", | ||
"mrcnn_bbox", "mrcnn_mask"]) | ||
elif init_with == "last": | ||
# Load the last model you trained and continue training | ||
model.load_weights(model.find_last(), by_name=True) | ||
|
||
# Train the head branches | ||
# Passing layers="heads" freezes all layers except the head | ||
# layers. You can also pass a regular expression to select | ||
# which layers to train by name pattern. | ||
|
||
#start_train = time.time() | ||
#model.train(dataset_train, dataset_val, | ||
# learning_rate=config.LEARNING_RATE, | ||
# epochs=10, | ||
# layers='heads') | ||
#end_train = time.time() | ||
#minutes = round((end_train - start_train) / 60, 2) | ||
#print(f'Training took {minutes} minutes') | ||
|
||
# Fine tune all layers | ||
# Passing layers="all" trains all layers. You can also | ||
# pass a regular expression to select which layers to | ||
# train by name pattern. | ||
start_train = time.time() | ||
model.train(dataset_train, dataset_val, | ||
learning_rate=config.LEARNING_RATE / 10, | ||
epochs=100, | ||
layers="all") | ||
end_train = time.time() | ||
minutes = round((end_train - start_train) / 60, 2) | ||
print(f'Training took {minutes} minutes') |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.