I’ve been following the wonderful tutorials by @NielsRogge to fine-tune DETR on a custom dataset. However, my predicted mask seems to be always empty after training.
Let’s say my dataset has 4 labels (in coco panoptic format). Looking at the model.config.id2label
of the pretrained DETR there are 250
different labels.
What would be the correct way to fine-tune the model to less labels (similar to fine-tuning a ViT classifier to 2 classes)?
Here is what I tried:
num_labels = 4
feature_extractor = DetrFeatureExtractor.from_pretrained(
"facebook/detr-resnet-50-panoptic", size=224, format="coco_panoptic"
)
config = DetrConfig.from_pretrained(
"facebook/detr-resnet-50-panoptic",
num_labels=num_labels
)
model = DetrForSegmentation.from_pretrained("facebook/detr-resnet-50-panoptic")
model.detr.class_labels_classifier = Linear(
in_features=model.config.hidden_size,
out_features=num_labels + 1, # +1 for "no object" class
)
# remove classifier weights and bias for pretrained model, since it has more classes than we want
state_dict = model.state_dict()
state_dict.pop("detr.class_labels_classifier.weight")
state_dict.pop("detr.class_labels_classifier.bias")
model.load_state_dict(state_dict, strict=False)
model.config = config
Even though my loss goes down, it appears that the model doesn’t learn. The post-processed predictions using feature_extractor.post_process_panoptic()
show the following (empty) result:
{'png_string': b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x01\xdf\x00\x00\x00\xe0\x08\x02\x00\x00\x00\xcd9\xfb\xc3\x00\x00\x01OIDATx\x9c\xed\xc11\x01\x00\x00\x00\xc2\xa0\xf5Om\x0c\x1f\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbe\x06\xea|\x00\x01\xd1K+\xbf\x00\x00\x00\x00IEND\xaeB`\x82',
'segments_info': []}
For feature_extractor.post_process_segmentation()
I get the following:
{'scores': tensor([], grad_fn=<IndexBackward0>),
'labels': tensor([], dtype=torch.int64),
'masks': tensor([], size=(0, 426, 640), dtype=torch.int64)}
Side Question: Would it make sense to lower the number of queries (from default 100) to something like 10 (from DetrFeatureExtractor
documentation: “Note that it’s good to have some slack”)?