Mask_RCNN icon indicating copy to clipboard operation
Mask_RCNN copied to clipboard

Mask R CNN predicts one class for everything

Open STASYA00 opened this issue 5 years ago • 8 comments

Hey guys! I'm using Mask R CNN on a custom dataset, very simple: solid background and objects divided into 4 classes, more or less of the same size, in the same place in the image. The dataset is balanced, every class has exactly the same number of images in the train and in the test. However, regardless of any parameters, length of training, anything, it predicts me one class only. I have tried to increase the weight for the class prediction - and it is dropping with every epoch, but the predictions remain the same - I always get the class 1 , even if in fact there is class 4 or 3. Here is the configuration:

image_size = 256
rpn_anchor_template = (2, 4, 8, 16, 32) # anchor sizes in pixels
rpn_anchor_scales = tuple(i * (image_size // 16) for i in rpn_anchor_template)

class NewConfig(Config):

    NAME = "industry"
 
    GPU_COUNT = 1
    IMAGES_PER_GPU = 2

    NUM_CLASSES = len(subset)+1 

    IMAGE_MAX_DIM = image_size
    IMAGE_MIN_DIM = image_size
 
    RPN_ANCHOR_SCALES = rpn_anchor_scales

    TRAIN_ROIS_PER_IMAGE = 8
    LOSS_WEIGHTS={'mrcnn_mask_loss': 1.0,
                  'rpn_class_loss': 5.0, 'mrcnn_class_loss': 5.0,
                  'mrcnn_bbox_loss': 1.0, 'rpn_bbox_loss': 2.0}
    STEPS_PER_EPOCH = 100
    VALIDATION_STEPS = STEPS_PER_EPOCH / 10
    
    def __init__(self, num_classes):
        self.NUM_CLASSES = num_classes
        super().__init__()
       
config = NewConfig(num_classes=len(subset)+1)
config.display()

Maybe there is something wrong here, because in the dataset the number of classes is correct.

STASYA00 avatar Sep 28 '19 09:09 STASYA00

What are the parameters passed to your model.load_weights() function?

ebernalg92 avatar Oct 07 '19 06:10 ebernalg92

@ebernalg92

model.load_weights(model_path, by_name=True,exclude=[ "mrcnn_class_logits", "mrcnn_bbox_fc","mrcnn_bbox", "mrcnn_mask"])

But actually, I also checked, and it changes the prediction from time to time (with the same weights, taken from the same epoch) which is strange, because for the same parameters it should be consistent, no?

STASYA00 avatar Oct 07 '19 09:10 STASYA00

yeah, i was experimenting the same issue, just use :

model.load_weights(model_path, by_name=True)

not excluding [ "mrcnn_class_logits", "mrcnn_bbox_fc","mrcnn_bbox", "mrcnn_mask"]

This is while doing inference this way

model = MaskRCNN( mode="inference", model_dir='./', config=cfg )

ebernalg92 avatar Oct 07 '19 11:10 ebernalg92

@ebernalg92 that worked!! Thank you so much, now it's super precise! But if it's not too difficult could you, please, explain, why?

STASYA00 avatar Oct 07 '19 12:10 STASYA00

Hey guys! I'm using Mask R CNN on a custom dataset, very simple: solid background and objects divided into 4 classes, more or less of the same size, in the same place in the image. The dataset is balanced, every class has exactly the same number of images in the train and in the test. However, regardless of any parameters, length of training, anything, it predicts me one class only. I have tried to increase the weight for the class prediction - and it is dropping with every epoch, but the predictions remain the same - I always get the class 1 , even if in fact there is class 4 or 3. Here is the configuration:

image_size = 256
rpn_anchor_template = (2, 4, 8, 16, 32) # anchor sizes in pixels
rpn_anchor_scales = tuple(i * (image_size // 16) for i in rpn_anchor_template)

class NewConfig(Config):

    NAME = "industry"
 
    GPU_COUNT = 1
    IMAGES_PER_GPU = 2

    NUM_CLASSES = len(subset)+1 

    IMAGE_MAX_DIM = image_size
    IMAGE_MIN_DIM = image_size
 
    RPN_ANCHOR_SCALES = rpn_anchor_scales

    TRAIN_ROIS_PER_IMAGE = 8
    LOSS_WEIGHTS={'mrcnn_mask_loss': 1.0,
                  'rpn_class_loss': 5.0, 'mrcnn_class_loss': 5.0,
                  'mrcnn_bbox_loss': 1.0, 'rpn_bbox_loss': 2.0}
    STEPS_PER_EPOCH = 100
    VALIDATION_STEPS = STEPS_PER_EPOCH / 10
    
    def __init__(self, num_classes):
        self.NUM_CLASSES = num_classes
        super().__init__()
       
config = NewConfig(num_classes=len(subset)+1)
config.display()

Maybe there is something wrong here, because in the dataset the number of classes is correct.

Dear STASYA00

I want to use Mask-RCNN to train on my custom dataset (just one class).

First of all, I use Labelme to create groundtruth for each image. Each image has a .json file as its ground-truth.

After that, I don't know what should I do...

I want to know how to convert my groundtruth file to a format that Mask-rcnn can use. Do you have any tools ?

Looking forward to hearing from you, thanks in advance.

With best regards, Ming

May-forever avatar Oct 08 '19 12:10 May-forever

@hjm1990818 If you have the json files as annotations, it should be enough. You can check in the Shapes and the Balloon samples, there is a class Dataset with the functions inside. You can copy it and change the functions a bit in order to take your input. I can give you my functions and if you still have problems, give me your telegram or email and I can help you.

# The function in the Dataset class that loads the information from the image
def load_image(self, dataset_dir, filename_annotation):
        
        annotations = json.load(open(os.path.join(ANNO_DIR, filename_annotation)))
        
        self.add_class('superclass', 1, 'class') # add all your classes with indices
            
        for a in range(len(annotations['annotations'])):
             if annotations['annotations'][a]['image_id'] in labels:
                    polygons = annotations['annotations'][a]['segmentation'] # information from  your annotation json file
                    image_path = os.path.join(new_dataset_dir, annotations['images'][a]['file_name']) # path to load the image, from your annotation file
                    self.add_image(
                         'shoes', # dataset name
                         class_ids=annotations['annotations'][a]['category_id'], # which class the image belongs to
                         image_id=annotations['images'][a]['id'],  # a unique image id
                         path=image_path,
                         width=annotations['images'][a]['width'],
                         height=annotations['images'][a]['height'],
                         polygons=polygons)

And then you also write a load_mask function that gets mask and class from your json and should return you a mask in a form of mask.astype(np.uint8) and class ids as np.array(class_ids,dtype=np.int32)

Basically that's it. And I would suggest you to put all the jsons in one json file and to load all the annotations from there directly. Then you do:

d=ShoeDataset()
d.load_image(DATA_DIR, filename_annotation) # add other arguments if you need them for your load_image function
d.prepare() # get dataset 

STASYA00 avatar Oct 08 '19 13:10 STASYA00

Hi, everyone I still meet the same problem. I used VIA to annotate about 80 images. My environment is Tensorflow gpu 1.6 + python3.6, the training looks good and no error, the segmentation is also good enough. But every time, the model predicts the object is a cat with almost 100%. I do not know where is the problem. Hope for help, appreciate so much. My codes of test are shown below:

`import os import mrcnn.visualize import cv2 import time from mrcnn.config import Config

import mrcnn.model as modellib

from datetime import datetime

Root directory of the project

ROOT_DIR = os.getcwd()

Root directory of the project

Directory to save logs and trained model

MODEL_DIR = os.path.join(ROOT_DIR, "logs")

Local path to trained weights file

COCO_MODEL_PATH = os.path.join(ROOT_DIR, "mask_rcnn_balloon_0100.h5")

Download COCO trained weights from Releases if needed

Directory of images to run detection on

IMAGE_DIR = os.path.join(ROOT_DIR, "images2")

class_names = ['BG', 'cat', 'dog'] class SimpleConfig(mrcnn.config.Config): NAME = "balloon" GPU_COUNT = 1 IMAGES_PER_GPU = 1 NUM_CLASSES = len(class_names)

import mrcnn.model

Create model object in inference mode.

model = modellib.MaskRCNN(mode="inference", model_dir=MODEL_DIR, config=SimpleConfig())

#model = mrcnn.model.MaskRCNN(mode="inference", model_dir=ROOT_DIR, config=SimpleConfig())

model.load_weights(filepath=COCO_MODEL_PATH, by_name=True)

class_names = ['BG', 'cat', 'dog']

Load a random image from the images folder

image = cv2.imread(r'C:\Users\Owner\Downloads\Mask_RCNN-2.1\images2\test6.jpg') image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

r = model.detect([image], verbose=1)

r = r[0] #print(r)

mrcnn.visualize.display_instances(image=image, boxes=r['rois'], masks=r['masks'], class_ids=r['class_ids'], class_names=class_names, scores=r['scores'])`

Fangshi1986 avatar Apr 12 '22 05:04 Fangshi1986

Hey guys! I'm using Mask R CNN on a custom dataset, very simple: solid background and objects divided into 4 classes, more or less of the same size, in the same place in the image. The dataset is balanced, every class has exactly the same number of images in the train and in the test. However, regardless of any parameters, length of training, anything, it predicts me one class only. I have tried to increase the weight for the class prediction - and it is dropping with every epoch, but the predictions remain the same - I always get the class 1 , even if in fact there is class 4 or 3. Here is the configuration:

image_size = 256
rpn_anchor_template = (2, 4, 8, 16, 32) # anchor sizes in pixels
rpn_anchor_scales = tuple(i * (image_size // 16) for i in rpn_anchor_template)

class NewConfig(Config):

    NAME = "industry"
 
    GPU_COUNT = 1
    IMAGES_PER_GPU = 2

    NUM_CLASSES = len(subset)+1 

    IMAGE_MAX_DIM = image_size
    IMAGE_MIN_DIM = image_size
 
    RPN_ANCHOR_SCALES = rpn_anchor_scales

    TRAIN_ROIS_PER_IMAGE = 8
    LOSS_WEIGHTS={'mrcnn_mask_loss': 1.0,
                  'rpn_class_loss': 5.0, 'mrcnn_class_loss': 5.0,
                  'mrcnn_bbox_loss': 1.0, 'rpn_bbox_loss': 2.0}
    STEPS_PER_EPOCH = 100
    VALIDATION_STEPS = STEPS_PER_EPOCH / 10
    
    def __init__(self, num_classes):
        self.NUM_CLASSES = num_classes
        super().__init__()
       
config = NewConfig(num_classes=len(subset)+1)
config.display()

Maybe there is something wrong here, because in the dataset the number of classes is correct.

Hi, i'm using Mask Rcnn for detection just one class , i habe some question how can i contact you , if you would like to help thanks

Aimen-Achi avatar Apr 28 '22 23:04 Aimen-Achi