Add D-FINE Model into Transformers (#36261)
Some checks failed
Release - Conda / build_and_package (push) Has been cancelled
Secret Leaks / trufflehog (push) Has been cancelled

* copy the last changes from broken PR

* small format

* some fixes and refactoring after review

* format

* add config attr for loss

* some fixes and refactoring

* fix copies

* fix style

* add test for d-fine resnet

* fix decoder layer prop

* fix dummies

* format init

* remove extra print

* refactor modeling, move resnet into separate folder

* fix resnet config

* change resnet on hgnet_v2, add clamp into decoder

* fix init

* fix config doc

* fix init

* fix dummies

* fix config docs

* fix hgnet_v2 config typo

* format modular

* add image classification for hgnet, some refactoring

* format tests

* fix dummies

* fix init

* fix style

* fix init for hgnet v2

* fix index.md, add init rnage for hgnet

* fix conversion

* add missing attr to encoder

* add loss for d-fine, add additional output for rt-detr decoder

* tests and docs fixes

* fix rt_detr v2 conversion

* some fixes for loos and decoder output

* some fixes for loss

* small fix for converted modeling

* add n model config, some todo comments for modular

* convert script adjustments and fixes, small refact

* remove extra output for rt_detr

* make some outputs optionsl, fix conversion

* some posr merge fixes

* small fix

* last field fix

* fix not split for hgnet_v2

* disable parallelism test for hgnet_v2 image classification

* skip multi gpu for d-fine

* adjust after merge init

* remove extra comment

* fix repo name references

* small fixes for tests

* Fix checkpoint path

* Fix consistency

* Fixing docs

---------

Co-authored-by: Pavel Iakubovskii <qubvel@gmail.com>
This commit is contained in:
Vladislav Bronzov
2025-04-29 13:17:55 +02:00
committed by GitHub
parent 4602059aae
commit 4abeb50f6e
24 changed files with 7711 additions and 4 deletions

View File

@@ -499,6 +499,8 @@
title: Helium title: Helium
- local: model_doc/herbert - local: model_doc/herbert
title: HerBERT title: HerBERT
- local: model_doc/hgnet_v2
title: HGNet-V2
- local: model_doc/ibert - local: model_doc/ibert
title: I-BERT title: I-BERT
- local: model_doc/jamba - local: model_doc/jamba
@@ -691,6 +693,8 @@
title: ConvNeXTV2 title: ConvNeXTV2
- local: model_doc/cvt - local: model_doc/cvt
title: CvT title: CvT
- local: model_doc/d_fine
title: D-FINE
- local: model_doc/dab-detr - local: model_doc/dab-detr
title: DAB-DETR title: DAB-DETR
- local: model_doc/deformable_detr - local: model_doc/deformable_detr

View File

@@ -0,0 +1,76 @@
<!--Copyright 2025 The HuggingFace Team. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
rendered properly in your Markdown viewer.
-->
# D-FINE
## Overview
The D-FINE model was proposed in [D-FINE: Redefine Regression Task in DETRs as Fine-grained Distribution Refinement](https://arxiv.org/abs/2410.13842) by
Yansong Peng, Hebei Li, Peixi Wu, Yueyi Zhang, Xiaoyan Sun, Feng Wu
The abstract from the paper is the following:
*We introduce D-FINE, a powerful real-time object detector that achieves outstanding localization precision by redefining the bounding box regression task in DETR models. D-FINE comprises two key components: Fine-grained Distribution Refinement (FDR) and Global Optimal Localization Self-Distillation (GO-LSD).
FDR transforms the regression process from predicting fixed coordinates to iteratively refining probability distributions, providing a fine-grained intermediate representation that significantly enhances localization accuracy. GO-LSD is a bidirectional optimization strategy that transfers localization knowledge from refined distributions to shallower layers through self-distillation, while also simplifying the residual prediction tasks for deeper layers. Additionally, D-FINE incorporates lightweight optimizations in computationally intensive modules and operations, achieving a better balance between speed and accuracy. Specifically, D-FINE-L / X achieves 54.0% / 55.8% AP on the COCO dataset at 124 / 78 FPS on an NVIDIA T4 GPU. When pretrained on Objects365, D-FINE-L / X attains 57.1% / 59.3% AP, surpassing all existing real-time detectors. Furthermore, our method significantly enhances the performance of a wide range of DETR models by up to 5.3% AP with negligible extra parameters and training costs. Our code and pretrained models: this https URL.*
This model was contributed by [VladOS95-cyber](https://github.com/VladOS95-cyber).
The original code can be found [here](https://github.com/Peterande/D-FINE).
## Usage tips
```python
>>> import torch
>>> from transformers.image_utils import load_image
>>> from transformers import DFineForObjectDetection, AutoImageProcessor
>>> url = 'http://images.cocodataset.org/val2017/000000039769.jpg'
>>> image = load_image(url)
>>> image_processor = AutoImageProcessor.from_pretrained("ustc-community/dfine_x_coco")
>>> model = DFineForObjectDetection.from_pretrained("ustc-community/dfine_x_coco")
>>> inputs = image_processor(images=image, return_tensors="pt")
>>> with torch.no_grad():
... outputs = model(**inputs)
>>> results = image_processor.post_process_object_detection(outputs, target_sizes=[(image.height, image.width)], threshold=0.5)
>>> for result in results:
... for score, label_id, box in zip(result["scores"], result["labels"], result["boxes"]):
... score, label = score.item(), label_id.item()
... box = [round(i, 2) for i in box.tolist()]
... print(f"{model.config.id2label[label]}: {score:.2f} {box}")
cat: 0.96 [344.49, 23.4, 639.84, 374.27]
cat: 0.96 [11.71, 53.52, 316.64, 472.33]
remote: 0.95 [40.46, 73.7, 175.62, 117.57]
sofa: 0.92 [0.59, 1.88, 640.25, 474.74]
remote: 0.89 [333.48, 77.04, 370.77, 187.3]
```
## DFineConfig
[[autodoc]] DFineConfig
## DFineModel
[[autodoc]] DFineModel
- forward
## DFineForObjectDetection
[[autodoc]] DFineForObjectDetection
- forward

View File

@@ -0,0 +1,46 @@
<!--Copyright 2025 The HuggingFace Team. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
⚠️ Note that this file is in Markdown but contain specific syntax for our doc-builder (similar to MDX) that may not be
rendered properly in your Markdown viewer.
-->
# HGNet-V2
## Overview
A HGNet-V2 (High Performance GPU Net) image classification model.
HGNet arhtictecture was proposed in [HGNET: A Hierarchical Feature Guided Network for Occupancy Flow Field Prediction](https://arxiv.org/abs/2407.01097) by
Zhan Chen, Chen Tang, Lu Xiong
The abstract from the HGNET paper is the following:
*Predicting the motion of multiple traffic participants has always been one of the most challenging tasks in autonomous driving. The recently proposed occupancy flow field prediction method has shown to be a more effective and scalable representation compared to general trajectory prediction methods. However, in complex multi-agent traffic scenarios, it remains difficult to model the interactions among various factors and the dependencies among prediction outputs at different time steps. In view of this, we propose a transformer-based hierarchical feature guided network (HGNET), which can efficiently extract features of agents and map information from visual and vectorized inputs, modeling multimodal interaction relationships. Second, we design the Feature-Guided Attention (FGAT) module to leverage the potential guiding effects between different prediction targets, thereby improving prediction accuracy. Additionally, to enhance the temporal consistency and causal relationships of the predictions, we propose a Time Series Memory framework to learn the conditional distribution models of the prediction outputs at future time steps from multivariate time series. The results demonstrate that our model exhibits competitive performance, which ranks 3rd in the 2024 Waymo Occupancy and Flow Prediction Challenge.*
This model was contributed by [VladOS95-cyber](https://github.com/VladOS95-cyber).
The original code can be found [here](https://github.com/PaddlePaddle/PaddleDetection/blob/develop/ppdet/modeling/backbones/hgnet_v2.py).
## HGNetV2Config
[[autodoc]] HGNetV2Config
## HGNetV2Backbone
[[autodoc]] HGNetV2Backbone
- forward
## HGNetV2ForImageClassification
[[autodoc]] HGNetV2ForImageClassification
- forward

View File

@@ -0,0 +1,385 @@
# Copyright 2025 The HuggingFace Team. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import torch
import torch.nn as nn
import torch.nn.functional as F
from ..utils import is_vision_available
from .loss_for_object_detection import (
box_iou,
)
from .loss_rt_detr import RTDetrHungarianMatcher, RTDetrLoss
if is_vision_available():
from transformers.image_transforms import center_to_corners_format
@torch.jit.unused
def _set_aux_loss(outputs_class, outputs_coord):
# this is a workaround to make torchscript happy, as torchscript
# doesn't support dictionary with non-homogeneous values, such
# as a dict having both a Tensor and a list.
return [{"logits": a, "pred_boxes": b} for a, b in zip(outputs_class, outputs_coord)]
@torch.jit.unused
def _set_aux_loss2(
outputs_class, outputs_coord, outputs_corners, outputs_ref, teacher_corners=None, teacher_logits=None
):
# this is a workaround to make torchscript happy, as torchscript
# doesn't support dictionary with non-homogeneous values, such
# as a dict having both a Tensor and a list.
return [
{
"logits": a,
"pred_boxes": b,
"pred_corners": c,
"ref_points": d,
"teacher_corners": teacher_corners,
"teacher_logits": teacher_logits,
}
for a, b, c, d in zip(outputs_class, outputs_coord, outputs_corners, outputs_ref)
]
def weighting_function(max_num_bins: int, up: torch.Tensor, reg_scale: int) -> torch.Tensor:
"""
Generates the non-uniform Weighting Function W(n) for bounding box regression.
Args:
max_num_bins (int): Max number of the discrete bins.
up (Tensor): Controls upper bounds of the sequence,
where maximum offset is ±up * H / W.
reg_scale (float): Controls the curvature of the Weighting Function.
Larger values result in flatter weights near the central axis W(max_num_bins/2)=0
and steeper weights at both ends.
Returns:
Tensor: Sequence of Weighting Function.
"""
upper_bound1 = abs(up[0]) * abs(reg_scale)
upper_bound2 = abs(up[0]) * abs(reg_scale) * 2
step = (upper_bound1 + 1) ** (2 / (max_num_bins - 2))
left_values = [-((step) ** i) + 1 for i in range(max_num_bins // 2 - 1, 0, -1)]
right_values = [(step) ** i - 1 for i in range(1, max_num_bins // 2)]
values = [-upper_bound2] + left_values + [torch.zeros_like(up[0][None])] + right_values + [upper_bound2]
values = [v if v.dim() > 0 else v.unsqueeze(0) for v in values]
values = torch.cat(values, 0)
return values
def translate_gt(gt: torch.Tensor, max_num_bins: int, reg_scale: int, up: torch.Tensor):
"""
Decodes bounding box ground truth (GT) values into distribution-based GT representations.
This function maps continuous GT values into discrete distribution bins, which can be used
for regression tasks in object detection models. It calculates the indices of the closest
bins to each GT value and assigns interpolation weights to these bins based on their proximity
to the GT value.
Args:
gt (Tensor): Ground truth bounding box values, shape (N, ).
max_num_bins (int): Maximum number of discrete bins for the distribution.
reg_scale (float): Controls the curvature of the Weighting Function.
up (Tensor): Controls the upper bounds of the Weighting Function.
Returns:
Tuple[Tensor, Tensor, Tensor]:
- indices (Tensor): Index of the left bin closest to each GT value, shape (N, ).
- weight_right (Tensor): Weight assigned to the right bin, shape (N, ).
- weight_left (Tensor): Weight assigned to the left bin, shape (N, ).
"""
gt = gt.reshape(-1)
function_values = weighting_function(max_num_bins, up, reg_scale)
# Find the closest left-side indices for each value
diffs = function_values.unsqueeze(0) - gt.unsqueeze(1)
mask = diffs <= 0
closest_left_indices = torch.sum(mask, dim=1) - 1
# Calculate the weights for the interpolation
indices = closest_left_indices.float()
weight_right = torch.zeros_like(indices)
weight_left = torch.zeros_like(indices)
valid_idx_mask = (indices >= 0) & (indices < max_num_bins)
valid_indices = indices[valid_idx_mask].long()
# Obtain distances
left_values = function_values[valid_indices]
right_values = function_values[valid_indices + 1]
left_diffs = torch.abs(gt[valid_idx_mask] - left_values)
right_diffs = torch.abs(right_values - gt[valid_idx_mask])
# Valid weights
weight_right[valid_idx_mask] = left_diffs / (left_diffs + right_diffs)
weight_left[valid_idx_mask] = 1.0 - weight_right[valid_idx_mask]
# Invalid weights (out of range)
invalid_idx_mask_neg = indices < 0
weight_right[invalid_idx_mask_neg] = 0.0
weight_left[invalid_idx_mask_neg] = 1.0
indices[invalid_idx_mask_neg] = 0.0
invalid_idx_mask_pos = indices >= max_num_bins
weight_right[invalid_idx_mask_pos] = 1.0
weight_left[invalid_idx_mask_pos] = 0.0
indices[invalid_idx_mask_pos] = max_num_bins - 0.1
return indices, weight_right, weight_left
def bbox2distance(points, bbox, max_num_bins, reg_scale, up, eps=0.1):
"""
Converts bounding box coordinates to distances from a reference point.
Args:
points (Tensor): (n, 4) [x, y, w, h], where (x, y) is the center.
bbox (Tensor): (n, 4) bounding boxes in "xyxy" format.
max_num_bins (float): Maximum bin value.
reg_scale (float): Controling curvarture of W(n).
up (Tensor): Controling upper bounds of W(n).
eps (float): Small value to ensure target < max_num_bins.
Returns:
Tensor: Decoded distances.
"""
reg_scale = abs(reg_scale)
left = (points[:, 0] - bbox[:, 0]) / (points[..., 2] / reg_scale + 1e-16) - 0.5 * reg_scale
top = (points[:, 1] - bbox[:, 1]) / (points[..., 3] / reg_scale + 1e-16) - 0.5 * reg_scale
right = (bbox[:, 2] - points[:, 0]) / (points[..., 2] / reg_scale + 1e-16) - 0.5 * reg_scale
bottom = (bbox[:, 3] - points[:, 1]) / (points[..., 3] / reg_scale + 1e-16) - 0.5 * reg_scale
four_lens = torch.stack([left, top, right, bottom], -1)
four_lens, weight_right, weight_left = translate_gt(four_lens, max_num_bins, reg_scale, up)
if max_num_bins is not None:
four_lens = four_lens.clamp(min=0, max=max_num_bins - eps)
return four_lens.reshape(-1).detach(), weight_right.detach(), weight_left.detach()
class DFineLoss(RTDetrLoss):
"""
This class computes the losses for D-FINE. The process happens in two steps: 1) we compute hungarian assignment
between ground truth boxes and the outputs of the model 2) we supervise each pair of matched ground-truth /
prediction (supervise class and box).
Args:
matcher (`DetrHungarianMatcher`):
Module able to compute a matching between targets and proposals.
weight_dict (`Dict`):
Dictionary relating each loss with its weights. These losses are configured in DFineConf as
`weight_loss_vfl`, `weight_loss_bbox`, `weight_loss_giou`, `weight_loss_fgl`, `weight_loss_ddf`
losses (`List[str]`):
List of all the losses to be applied. See `get_loss` for a list of all available losses.
alpha (`float`):
Parameter alpha used to compute the focal loss.
gamma (`float`):
Parameter gamma used to compute the focal loss.
eos_coef (`float`):
Relative classification weight applied to the no-object category.
num_classes (`int`):
Number of object categories, omitting the special no-object category.
"""
def __init__(self, config):
super().__init__(config)
self.matcher = RTDetrHungarianMatcher(config)
self.max_num_bins = config.max_num_bins
self.weight_dict = {
"loss_vfl": config.weight_loss_vfl,
"loss_bbox": config.weight_loss_bbox,
"loss_giou": config.weight_loss_giou,
"loss_fgl": config.weight_loss_fgl,
"loss_ddf": config.weight_loss_ddf,
}
self.losses = ["vfl", "boxes", "local"]
self.reg_scale = config.reg_scale
self.up = nn.Parameter(torch.tensor([config.up]), requires_grad=False)
def unimodal_distribution_focal_loss(
self, pred, label, weight_right, weight_left, weight=None, reduction="sum", avg_factor=None
):
dis_left = label.long()
dis_right = dis_left + 1
loss = F.cross_entropy(pred, dis_left, reduction="none") * weight_left.reshape(-1) + F.cross_entropy(
pred, dis_right, reduction="none"
) * weight_right.reshape(-1)
if weight is not None:
weight = weight.float()
loss = loss * weight
if avg_factor is not None:
loss = loss.sum() / avg_factor
elif reduction == "mean":
loss = loss.mean()
elif reduction == "sum":
loss = loss.sum()
return loss
def loss_local(self, outputs, targets, indices, num_boxes, T=5):
"""Compute Fine-Grained Localization (FGL) Loss
and Decoupled Distillation Focal (DDF) Loss."""
losses = {}
if "pred_corners" in outputs:
idx = self._get_source_permutation_idx(indices)
target_boxes = torch.cat([t["boxes"][i] for t, (_, i) in zip(targets, indices)], dim=0)
pred_corners = outputs["pred_corners"][idx].reshape(-1, (self.max_num_bins + 1))
ref_points = outputs["ref_points"][idx].detach()
with torch.no_grad():
self.fgl_targets = bbox2distance(
ref_points,
center_to_corners_format(target_boxes),
self.max_num_bins,
self.reg_scale,
self.up,
)
target_corners, weight_right, weight_left = self.fgl_targets
ious = torch.diag(
box_iou(center_to_corners_format(outputs["pred_boxes"][idx]), center_to_corners_format(target_boxes))[
0
]
)
weight_targets = ious.unsqueeze(-1).repeat(1, 1, 4).reshape(-1).detach()
losses["loss_fgl"] = self.unimodal_distribution_focal_loss(
pred_corners,
target_corners,
weight_right,
weight_left,
weight_targets,
avg_factor=num_boxes,
)
pred_corners = outputs["pred_corners"].reshape(-1, (self.max_num_bins + 1))
target_corners = outputs["teacher_corners"].reshape(-1, (self.max_num_bins + 1))
if torch.equal(pred_corners, target_corners):
losses["loss_ddf"] = pred_corners.sum() * 0
else:
weight_targets_local = outputs["teacher_logits"].sigmoid().max(dim=-1)[0]
mask = torch.zeros_like(weight_targets_local, dtype=torch.bool)
mask[idx] = True
mask = mask.unsqueeze(-1).repeat(1, 1, 4).reshape(-1)
weight_targets_local[idx] = ious.reshape_as(weight_targets_local[idx]).to(weight_targets_local.dtype)
weight_targets_local = weight_targets_local.unsqueeze(-1).repeat(1, 1, 4).reshape(-1).detach()
loss_match_local = (
weight_targets_local
* (T**2)
* (
nn.KLDivLoss(reduction="none")(
F.log_softmax(pred_corners / T, dim=1),
F.softmax(target_corners.detach() / T, dim=1),
)
).sum(-1)
)
batch_scale = 1 / outputs["pred_boxes"].shape[0] # it should be refined
self.num_pos, self.num_neg = (
(mask.sum() * batch_scale) ** 0.5,
((~mask).sum() * batch_scale) ** 0.5,
)
loss_match_local1 = loss_match_local[mask].mean() if mask.any() else 0
loss_match_local2 = loss_match_local[~mask].mean() if (~mask).any() else 0
losses["loss_ddf"] = (loss_match_local1 * self.num_pos + loss_match_local2 * self.num_neg) / (
self.num_pos + self.num_neg
)
return losses
def get_loss(self, loss, outputs, targets, indices, num_boxes):
loss_map = {
"cardinality": self.loss_cardinality,
"local": self.loss_local,
"boxes": self.loss_boxes,
"focal": self.loss_labels_focal,
"vfl": self.loss_labels_vfl,
}
if loss not in loss_map:
raise ValueError(f"Loss {loss} not supported")
return loss_map[loss](outputs, targets, indices, num_boxes)
def DFineForObjectDetectionLoss(
logits,
labels,
device,
pred_boxes,
config,
outputs_class=None,
outputs_coord=None,
enc_topk_logits=None,
enc_topk_bboxes=None,
denoising_meta_values=None,
predicted_corners=None,
initial_reference_points=None,
**kwargs,
):
criterion = DFineLoss(config)
criterion.to(device)
# Second: compute the losses, based on outputs and labels
outputs_loss = {}
outputs_loss["logits"] = logits
outputs_loss["pred_boxes"] = pred_boxes.clamp(min=0, max=1)
auxiliary_outputs = None
if config.auxiliary_loss:
if denoising_meta_values is not None:
dn_out_coord, outputs_coord = torch.split(
outputs_coord.clamp(min=0, max=1), denoising_meta_values["dn_num_split"], dim=2
)
dn_out_class, outputs_class = torch.split(outputs_class, denoising_meta_values["dn_num_split"], dim=2)
dn_out_corners, out_corners = torch.split(predicted_corners, denoising_meta_values["dn_num_split"], dim=2)
dn_out_refs, out_refs = torch.split(initial_reference_points, denoising_meta_values["dn_num_split"], dim=2)
auxiliary_outputs = _set_aux_loss2(
outputs_class[:, :-1].transpose(0, 1),
outputs_coord[:, :-1].transpose(0, 1),
out_corners[:, :-1].transpose(0, 1),
out_refs[:, :-1].transpose(0, 1),
out_corners[:, -1],
outputs_class[:, -1],
)
outputs_loss["auxiliary_outputs"] = auxiliary_outputs
outputs_loss["auxiliary_outputs"].extend(
_set_aux_loss([enc_topk_logits], [enc_topk_bboxes.clamp(min=0, max=1)])
)
dn_auxiliary_outputs = _set_aux_loss2(
dn_out_class.transpose(0, 1),
dn_out_coord.transpose(0, 1),
dn_out_corners.transpose(0, 1),
dn_out_refs.transpose(0, 1),
dn_out_corners[:, -1],
dn_out_class[:, -1],
)
outputs_loss["dn_auxiliary_outputs"] = dn_auxiliary_outputs
outputs_loss["denoising_meta_values"] = denoising_meta_values
loss_dict = criterion(outputs_loss, labels)
loss = sum(loss_dict.values())
return loss, loss_dict, auxiliary_outputs

View File

@@ -18,6 +18,7 @@ import torch
import torch.nn as nn import torch.nn as nn
from torch.nn import BCEWithLogitsLoss, MSELoss from torch.nn import BCEWithLogitsLoss, MSELoss
from .loss_d_fine import DFineForObjectDetectionLoss
from .loss_deformable_detr import DeformableDetrForObjectDetectionLoss, DeformableDetrForSegmentationLoss from .loss_deformable_detr import DeformableDetrForObjectDetectionLoss, DeformableDetrForSegmentationLoss
from .loss_for_object_detection import ForObjectDetectionLoss, ForSegmentationLoss from .loss_for_object_detection import ForObjectDetectionLoss, ForSegmentationLoss
from .loss_grounding_dino import GroundingDinoForObjectDetectionLoss from .loss_grounding_dino import GroundingDinoForObjectDetectionLoss
@@ -156,4 +157,5 @@ LOSS_MAPPING = {
"ConditionalDetrForSegmentation": DeformableDetrForSegmentationLoss, "ConditionalDetrForSegmentation": DeformableDetrForSegmentationLoss,
"RTDetrForObjectDetection": RTDetrForObjectDetectionLoss, "RTDetrForObjectDetection": RTDetrForObjectDetectionLoss,
"RTDetrV2ForObjectDetection": RTDetrForObjectDetectionLoss, "RTDetrV2ForObjectDetection": RTDetrForObjectDetectionLoss,
"DFineForObjectDetection": DFineForObjectDetectionLoss,
} }

View File

@@ -70,6 +70,7 @@ if TYPE_CHECKING:
from .cpmant import * from .cpmant import *
from .ctrl import * from .ctrl import *
from .cvt import * from .cvt import *
from .d_fine import *
from .dab_detr import * from .dab_detr import *
from .dac import * from .dac import *
from .data2vec import * from .data2vec import *
@@ -133,6 +134,7 @@ if TYPE_CHECKING:
from .groupvit import * from .groupvit import *
from .helium import * from .helium import *
from .herbert import * from .herbert import *
from .hgnet_v2 import *
from .hiera import * from .hiera import *
from .hubert import * from .hubert import *
from .ibert import * from .ibert import *

View File

@@ -82,6 +82,7 @@ CONFIG_MAPPING_NAMES = OrderedDict(
("cpmant", "CpmAntConfig"), ("cpmant", "CpmAntConfig"),
("ctrl", "CTRLConfig"), ("ctrl", "CTRLConfig"),
("cvt", "CvtConfig"), ("cvt", "CvtConfig"),
("d_fine", "DFineConfig"),
("dab-detr", "DabDetrConfig"), ("dab-detr", "DabDetrConfig"),
("dac", "DacConfig"), ("dac", "DacConfig"),
("data2vec-audio", "Data2VecAudioConfig"), ("data2vec-audio", "Data2VecAudioConfig"),
@@ -151,6 +152,7 @@ CONFIG_MAPPING_NAMES = OrderedDict(
("grounding-dino", "GroundingDinoConfig"), ("grounding-dino", "GroundingDinoConfig"),
("groupvit", "GroupViTConfig"), ("groupvit", "GroupViTConfig"),
("helium", "HeliumConfig"), ("helium", "HeliumConfig"),
("hgnet_v2", "HGNetV2Config"),
("hiera", "HieraConfig"), ("hiera", "HieraConfig"),
("hubert", "HubertConfig"), ("hubert", "HubertConfig"),
("ibert", "IBertConfig"), ("ibert", "IBertConfig"),
@@ -436,6 +438,7 @@ MODEL_NAMES_MAPPING = OrderedDict(
("cpmant", "CPM-Ant"), ("cpmant", "CPM-Ant"),
("ctrl", "CTRL"), ("ctrl", "CTRL"),
("cvt", "CvT"), ("cvt", "CvT"),
("d_fine", "D-FINE"),
("dab-detr", "DAB-DETR"), ("dab-detr", "DAB-DETR"),
("dac", "DAC"), ("dac", "DAC"),
("data2vec-audio", "Data2VecAudio"), ("data2vec-audio", "Data2VecAudio"),
@@ -513,6 +516,7 @@ MODEL_NAMES_MAPPING = OrderedDict(
("groupvit", "GroupViT"), ("groupvit", "GroupViT"),
("helium", "Helium"), ("helium", "Helium"),
("herbert", "HerBERT"), ("herbert", "HerBERT"),
("hgnet_v2", "HGNet-V2"),
("hiera", "Hiera"), ("hiera", "Hiera"),
("hubert", "Hubert"), ("hubert", "Hubert"),
("ibert", "I-BERT"), ("ibert", "I-BERT"),

View File

@@ -80,6 +80,7 @@ MODEL_MAPPING_NAMES = OrderedDict(
("cpmant", "CpmAntModel"), ("cpmant", "CpmAntModel"),
("ctrl", "CTRLModel"), ("ctrl", "CTRLModel"),
("cvt", "CvtModel"), ("cvt", "CvtModel"),
("d_fine", "DFineModel"),
("dab-detr", "DabDetrModel"), ("dab-detr", "DabDetrModel"),
("dac", "DacModel"), ("dac", "DacModel"),
("data2vec-audio", "Data2VecAudioModel"), ("data2vec-audio", "Data2VecAudioModel"),
@@ -142,6 +143,7 @@ MODEL_MAPPING_NAMES = OrderedDict(
("grounding-dino", "GroundingDinoModel"), ("grounding-dino", "GroundingDinoModel"),
("groupvit", "GroupViTModel"), ("groupvit", "GroupViTModel"),
("helium", "HeliumModel"), ("helium", "HeliumModel"),
("hgnet_v2", "HGNetV2Backbone"),
("hiera", "HieraModel"), ("hiera", "HieraModel"),
("hubert", "HubertModel"), ("hubert", "HubertModel"),
("ibert", "IBertModel"), ("ibert", "IBertModel"),
@@ -729,6 +731,7 @@ MODEL_FOR_IMAGE_CLASSIFICATION_MAPPING_NAMES = OrderedDict(
), ),
("efficientnet", "EfficientNetForImageClassification"), ("efficientnet", "EfficientNetForImageClassification"),
("focalnet", "FocalNetForImageClassification"), ("focalnet", "FocalNetForImageClassification"),
("hgnet_v2", "HGNetV2ForImageClassification"),
("hiera", "HieraForImageClassification"), ("hiera", "HieraForImageClassification"),
("ijepa", "IJepaForImageClassification"), ("ijepa", "IJepaForImageClassification"),
("imagegpt", "ImageGPTForImageClassification"), ("imagegpt", "ImageGPTForImageClassification"),
@@ -945,6 +948,7 @@ MODEL_FOR_OBJECT_DETECTION_MAPPING_NAMES = OrderedDict(
[ [
# Model for Object Detection mapping # Model for Object Detection mapping
("conditional_detr", "ConditionalDetrForObjectDetection"), ("conditional_detr", "ConditionalDetrForObjectDetection"),
("d_fine", "DFineForObjectDetection"),
("dab-detr", "DabDetrForObjectDetection"), ("dab-detr", "DabDetrForObjectDetection"),
("deformable_detr", "DeformableDetrForObjectDetection"), ("deformable_detr", "DeformableDetrForObjectDetection"),
("deta", "DetaForObjectDetection"), ("deta", "DetaForObjectDetection"),
@@ -1476,6 +1480,7 @@ MODEL_FOR_BACKBONE_MAPPING_NAMES = OrderedDict(
("dinov2", "Dinov2Backbone"), ("dinov2", "Dinov2Backbone"),
("dinov2_with_registers", "Dinov2WithRegistersBackbone"), ("dinov2_with_registers", "Dinov2WithRegistersBackbone"),
("focalnet", "FocalNetBackbone"), ("focalnet", "FocalNetBackbone"),
("hgnet_v2", "HGNetV2Backbone"),
("hiera", "HieraBackbone"), ("hiera", "HieraBackbone"),
("maskformer-swin", "MaskFormerSwinBackbone"), ("maskformer-swin", "MaskFormerSwinBackbone"),
("nat", "NatBackbone"), ("nat", "NatBackbone"),

View File

@@ -0,0 +1,29 @@
# Copyright 2025 The HuggingFace Team. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import TYPE_CHECKING
from ...utils import _LazyModule
from ...utils.import_utils import define_import_structure
if TYPE_CHECKING:
from .configuration_d_fine import *
from .modeling_d_fine import *
else:
import sys
_file = globals()["__file__"]
sys.modules[__name__] = _LazyModule(__name__, _file, define_import_structure(_file), module_spec=__spec__)

View File

@@ -0,0 +1,425 @@
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
# This file was automatically generated from src/transformers/models/d_fine/modular_d_fine.py.
# Do NOT edit this file manually as any edits will be overwritten by the generation of
# the file from the modular. If any change should be done, please apply the change to the
# modular_d_fine.py file directly. One of our CI enforces this.
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
# coding=utf-8
# Copyright 2025 Baidu Inc and The HuggingFace Inc. team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from ...configuration_utils import PretrainedConfig
from ...utils import logging
from ...utils.backbone_utils import verify_backbone_config_arguments
from ..auto import CONFIG_MAPPING
logger = logging.get_logger(__name__)
# TODO: Attribute map assignment logic should be fixed in modular
# as well as super() call parsing becuase otherwise we cannot re-write args after initialization
class DFineConfig(PretrainedConfig):
"""
This is the configuration class to store the configuration of a [`DFineModel`]. It is used to instantiate a D-FINE
model according to the specified arguments, defining the model architecture. Instantiating a configuration with the
defaults will yield a similar configuration to that of D-FINE-X-COCO "[ustc-community/dfine_x_coco"](https://huggingface.co/ustc-community/dfine_x_coco").
Configuration objects inherit from [`PretrainedConfig`] and can be used to control the model outputs. Read the
documentation from [`PretrainedConfig`] for more information.
Args:
initializer_range (`float`, *optional*, defaults to 0.01):
The standard deviation of the truncated_normal_initializer for initializing all weight matrices.
initializer_bias_prior_prob (`float`, *optional*):
The prior probability used by the bias initializer to initialize biases for `enc_score_head` and `class_embed`.
If `None`, `prior_prob` computed as `prior_prob = 1 / (num_labels + 1)` while initializing model weights.
layer_norm_eps (`float`, *optional*, defaults to 1e-05):
The epsilon used by the layer normalization layers.
batch_norm_eps (`float`, *optional*, defaults to 1e-05):
The epsilon used by the batch normalization layers.
backbone_config (`Dict`, *optional*, defaults to `RTDetrResNetConfig()`):
The configuration of the backbone model.
backbone (`str`, *optional*):
Name of backbone to use when `backbone_config` is `None`. If `use_pretrained_backbone` is `True`, this
will load the corresponding pretrained weights from the timm or transformers library. If `use_pretrained_backbone`
is `False`, this loads the backbone's config and uses that to initialize the backbone with random weights.
use_pretrained_backbone (`bool`, *optional*, defaults to `False`):
Whether to use pretrained weights for the backbone.
use_timm_backbone (`bool`, *optional*, defaults to `False`):
Whether to load `backbone` from the timm library. If `False`, the backbone is loaded from the transformers
library.
freeze_backbone_batch_norms (`bool`, *optional*, defaults to `True`):
Whether to freeze the batch normalization layers in the backbone.
backbone_kwargs (`dict`, *optional*):
Keyword arguments to be passed to AutoBackbone when loading from a checkpoint
e.g. `{'out_indices': (0, 1, 2, 3)}`. Cannot be specified if `backbone_config` is set.
encoder_hidden_dim (`int`, *optional*, defaults to 256):
Dimension of the layers in hybrid encoder.
encoder_in_channels (`list`, *optional*, defaults to `[512, 1024, 2048]`):
Multi level features input for encoder.
feat_strides (`List[int]`, *optional*, defaults to `[8, 16, 32]`):
Strides used in each feature map.
encoder_layers (`int`, *optional*, defaults to 1):
Total of layers to be used by the encoder.
encoder_ffn_dim (`int`, *optional*, defaults to 1024):
Dimension of the "intermediate" (often named feed-forward) layer in decoder.
encoder_attention_heads (`int`, *optional*, defaults to 8):
Number of attention heads for each attention layer in the Transformer encoder.
dropout (`float`, *optional*, defaults to 0.0):
The ratio for all dropout layers.
activation_dropout (`float`, *optional*, defaults to 0.0):
The dropout ratio for activations inside the fully connected layer.
encode_proj_layers (`List[int]`, *optional*, defaults to `[2]`):
Indexes of the projected layers to be used in the encoder.
positional_encoding_temperature (`int`, *optional*, defaults to 10000):
The temperature parameter used to create the positional encodings.
encoder_activation_function (`str`, *optional*, defaults to `"gelu"`):
The non-linear activation function (function or string) in the encoder and pooler. If string, `"gelu"`,
`"relu"`, `"silu"` and `"gelu_new"` are supported.
activation_function (`str`, *optional*, defaults to `"silu"`):
The non-linear activation function (function or string) in the general layer. If string, `"gelu"`,
`"relu"`, `"silu"` and `"gelu_new"` are supported.
eval_size (`Tuple[int, int]`, *optional*):
Height and width used to computes the effective height and width of the position embeddings after taking
into account the stride.
normalize_before (`bool`, *optional*, defaults to `False`):
Determine whether to apply layer normalization in the transformer encoder layer before self-attention and
feed-forward modules.
hidden_expansion (`float`, *optional*, defaults to 1.0):
Expansion ratio to enlarge the dimension size of RepVGGBlock and CSPRepLayer.
d_model (`int`, *optional*, defaults to 256):
Dimension of the layers exclude hybrid encoder.
num_queries (`int`, *optional*, defaults to 300):
Number of object queries.
decoder_in_channels (`list`, *optional*, defaults to `[256, 256, 256]`):
Multi level features dimension for decoder
decoder_ffn_dim (`int`, *optional*, defaults to 1024):
Dimension of the "intermediate" (often named feed-forward) layer in decoder.
num_feature_levels (`int`, *optional*, defaults to 3):
The number of input feature levels.
decoder_n_points (`int`, *optional*, defaults to 4):
The number of sampled keys in each feature level for each attention head in the decoder.
decoder_layers (`int`, *optional*, defaults to 6):
Number of decoder layers.
decoder_attention_heads (`int`, *optional*, defaults to 8):
Number of attention heads for each attention layer in the Transformer decoder.
decoder_activation_function (`str`, *optional*, defaults to `"relu"`):
The non-linear activation function (function or string) in the decoder. If string, `"gelu"`,
`"relu"`, `"silu"` and `"gelu_new"` are supported.
attention_dropout (`float`, *optional*, defaults to 0.0):
The dropout ratio for the attention probabilities.
num_denoising (`int`, *optional*, defaults to 100):
The total number of denoising tasks or queries to be used for contrastive denoising.
label_noise_ratio (`float`, *optional*, defaults to 0.5):
The fraction of denoising labels to which random noise should be added.
box_noise_scale (`float`, *optional*, defaults to 1.0):
Scale or magnitude of noise to be added to the bounding boxes.
learn_initial_query (`bool`, *optional*, defaults to `False`):
Indicates whether the initial query embeddings for the decoder should be learned during training
anchor_image_size (`Tuple[int, int]`, *optional*):
Height and width of the input image used during evaluation to generate the bounding box anchors. If None, automatic generate anchor is applied.
with_box_refine (`bool`, *optional*, defaults to `True`):
Whether to apply iterative bounding box refinement, where each decoder layer refines the bounding boxes
based on the predictions from the previous layer.
is_encoder_decoder (`bool`, *optional*, defaults to `True`):
Whether the architecture has an encoder decoder structure.
matcher_alpha (`float`, *optional*, defaults to 0.25):
Parameter alpha used by the Hungarian Matcher.
matcher_gamma (`float`, *optional*, defaults to 2.0):
Parameter gamma used by the Hungarian Matcher.
matcher_class_cost (`float`, *optional*, defaults to 2.0):
The relative weight of the class loss used by the Hungarian Matcher.
matcher_bbox_cost (`float`, *optional*, defaults to 5.0):
The relative weight of the bounding box loss used by the Hungarian Matcher.
matcher_giou_cost (`float`, *optional*, defaults to 2.0):
The relative weight of the giou loss of used by the Hungarian Matcher.
use_focal_loss (`bool`, *optional*, defaults to `True`):
Parameter informing if focal focal should be used.
auxiliary_loss (`bool`, *optional*, defaults to `True`):
Whether auxiliary decoding losses (loss at each decoder layer) are to be used.
focal_loss_alpha (`float`, *optional*, defaults to 0.75):
Parameter alpha used to compute the focal loss.
focal_loss_gamma (`float`, *optional*, defaults to 2.0):
Parameter gamma used to compute the focal loss.
weight_loss_vfl (`float`, *optional*, defaults to 1.0):
Relative weight of the varifocal loss in the object detection loss.
weight_loss_bbox (`float`, *optional*, defaults to 5.0):
Relative weight of the L1 bounding box loss in the object detection loss.
weight_loss_giou (`float`, *optional*, defaults to 2.0):
Relative weight of the generalized IoU loss in the object detection loss.
weight_loss_fgl (`float`, *optional*, defaults to 0.15):
Relative weight of the fine-grained localization loss in the object detection loss.
weight_loss_ddf (`float`, *optional*, defaults to 1.5):
Relative weight of the decoupled distillation focal loss in the object detection loss.
eos_coefficient (`float`, *optional*, defaults to 0.0001):
Relative classification weight of the 'no-object' class in the object detection loss.
eval_idx (`int`, *optional*, defaults to -1):
Index of the decoder layer to use for evaluation. If negative, counts from the end
(e.g., -1 means use the last layer). This allows for early prediction in the decoder
stack while still training later layers.
layer_scale (`float`, *optional*, defaults to `1.0`):
Scaling factor for the hidden dimension in later decoder layers. Used to adjust the
model capacity after the evaluation layer.
max_num_bins (`int`, *optional*, defaults to 32):
Maximum number of bins for the distribution-guided bounding box refinement.
Higher values allow for more fine-grained localization but increase computation.
reg_scale (`float`, *optional*, defaults to 4.0):
Scale factor for the regression distribution. Controls the range and granularity
of the bounding box refinement process.
depth_mult (`float`, *optional*, defaults to 1.0):
Multiplier for the number of blocks in RepNCSPELAN4 layers. Used to scale the model's
depth while maintaining its architecture.
top_prob_values (`int`, *optional*, defaults to 4):
Number of top probability values to consider from each corner's distribution.
lqe_hidden_dim (`int`, *optional*, defaults to 64):
Hidden dimension size for the Location Quality Estimator (LQE) network.
lqe_layers (`int`, *optional*, defaults to 2):
Number of layers in the Location Quality Estimator MLP.
decoder_offset_scale (`float`, *optional*, defaults to 0.5):
Offset scale used in deformable attention.
decoder_method (`str`, *optional*, defaults to `"default"`):
The method to use for the decoder: `"default"` or `"discrete"`.
up (`float`, *optional*, defaults to 0.5):
Controls the upper bounds of the Weighting Function.
"""
model_type = "d_fine"
layer_types = ["basic", "bottleneck"]
attribute_map = {
"hidden_size": "d_model",
"num_attention_heads": "encoder_attention_heads",
}
def __init__(
self,
initializer_range=0.01,
initializer_bias_prior_prob=None,
layer_norm_eps=1e-5,
batch_norm_eps=1e-5,
# backbone
backbone_config=None,
backbone=None,
use_pretrained_backbone=False,
use_timm_backbone=False,
freeze_backbone_batch_norms=True,
backbone_kwargs=None,
# encoder HybridEncoder
encoder_hidden_dim=256,
encoder_in_channels=[512, 1024, 2048],
feat_strides=[8, 16, 32],
encoder_layers=1,
encoder_ffn_dim=1024,
encoder_attention_heads=8,
dropout=0.0,
activation_dropout=0.0,
encode_proj_layers=[2],
positional_encoding_temperature=10000,
encoder_activation_function="gelu",
activation_function="silu",
eval_size=None,
normalize_before=False,
hidden_expansion=1.0,
# decoder DFineTransformer
d_model=256,
num_queries=300,
decoder_in_channels=[256, 256, 256],
decoder_ffn_dim=1024,
num_feature_levels=3,
decoder_n_points=4,
decoder_layers=6,
decoder_attention_heads=8,
decoder_activation_function="relu",
attention_dropout=0.0,
num_denoising=100,
label_noise_ratio=0.5,
box_noise_scale=1.0,
learn_initial_query=False,
anchor_image_size=None,
with_box_refine=True,
is_encoder_decoder=True,
# Loss
matcher_alpha=0.25,
matcher_gamma=2.0,
matcher_class_cost=2.0,
matcher_bbox_cost=5.0,
matcher_giou_cost=2.0,
use_focal_loss=True,
auxiliary_loss=True,
focal_loss_alpha=0.75,
focal_loss_gamma=2.0,
weight_loss_vfl=1.0,
weight_loss_bbox=5.0,
weight_loss_giou=2.0,
weight_loss_fgl=0.15,
weight_loss_ddf=1.5,
eos_coefficient=1e-4,
eval_idx=-1,
layer_scale=1,
max_num_bins=32,
reg_scale=4.0,
depth_mult=1.0,
top_prob_values=4,
lqe_hidden_dim=64,
lqe_layers=2,
decoder_offset_scale=0.5,
decoder_method="default",
up=0.5,
**kwargs,
):
self.initializer_range = initializer_range
self.initializer_bias_prior_prob = initializer_bias_prior_prob
self.layer_norm_eps = layer_norm_eps
self.batch_norm_eps = batch_norm_eps
# backbone
if backbone_config is None and backbone is None:
logger.info(
"`backbone_config` and `backbone` are `None`. Initializing the config with the default `HGNet-V2` backbone."
)
backbone_model_type = "hgnet_v2"
config_class = CONFIG_MAPPING[backbone_model_type]
# this will map it to RTDetrResNetConfig
# note: we can instead create HGNetV2Config
# and we would need to create HGNetV2Backbone
backbone_config = config_class(
num_channels=3,
embedding_size=64,
hidden_sizes=[256, 512, 1024, 2048],
depths=[3, 4, 6, 3],
layer_type="bottleneck",
hidden_act="relu",
downsample_in_first_stage=False,
downsample_in_bottleneck=False,
out_features=None,
out_indices=[2, 3, 4],
)
elif isinstance(backbone_config, dict):
backbone_model_type = backbone_config.pop("model_type")
config_class = CONFIG_MAPPING[backbone_model_type]
backbone_config = config_class.from_dict(backbone_config)
verify_backbone_config_arguments(
use_timm_backbone=use_timm_backbone,
use_pretrained_backbone=use_pretrained_backbone,
backbone=backbone,
backbone_config=backbone_config,
backbone_kwargs=backbone_kwargs,
)
self.backbone_config = backbone_config
self.backbone = backbone
self.use_pretrained_backbone = use_pretrained_backbone
self.use_timm_backbone = use_timm_backbone
self.freeze_backbone_batch_norms = freeze_backbone_batch_norms
self.backbone_kwargs = backbone_kwargs
# encoder
self.encoder_hidden_dim = encoder_hidden_dim
self.encoder_in_channels = encoder_in_channels
self.feat_strides = feat_strides
self.encoder_attention_heads = encoder_attention_heads
self.encoder_ffn_dim = encoder_ffn_dim
self.dropout = dropout
self.activation_dropout = activation_dropout
self.encode_proj_layers = encode_proj_layers
self.encoder_layers = encoder_layers
self.positional_encoding_temperature = positional_encoding_temperature
self.eval_size = eval_size
self.normalize_before = normalize_before
self.encoder_activation_function = encoder_activation_function
self.activation_function = activation_function
self.hidden_expansion = hidden_expansion
# decoder
self.d_model = d_model
self.num_queries = num_queries
self.decoder_ffn_dim = decoder_ffn_dim
self.decoder_in_channels = decoder_in_channels
self.num_feature_levels = num_feature_levels
self.decoder_n_points = decoder_n_points
self.decoder_layers = decoder_layers
self.decoder_attention_heads = decoder_attention_heads
self.decoder_activation_function = decoder_activation_function
self.attention_dropout = attention_dropout
self.num_denoising = num_denoising
self.label_noise_ratio = label_noise_ratio
self.box_noise_scale = box_noise_scale
self.learn_initial_query = learn_initial_query
self.anchor_image_size = anchor_image_size
self.auxiliary_loss = auxiliary_loss
self.with_box_refine = with_box_refine
# Loss
self.matcher_alpha = matcher_alpha
self.matcher_gamma = matcher_gamma
self.matcher_class_cost = matcher_class_cost
self.matcher_bbox_cost = matcher_bbox_cost
self.matcher_giou_cost = matcher_giou_cost
self.use_focal_loss = use_focal_loss
self.focal_loss_alpha = focal_loss_alpha
self.focal_loss_gamma = focal_loss_gamma
self.weight_loss_vfl = weight_loss_vfl
self.weight_loss_bbox = weight_loss_bbox
self.weight_loss_giou = weight_loss_giou
self.weight_loss_fgl = weight_loss_fgl
self.weight_loss_ddf = weight_loss_ddf
self.eos_coefficient = eos_coefficient
# add the new attributes with the given values or defaults
self.eval_idx = eval_idx
self.layer_scale = layer_scale
self.max_num_bins = max_num_bins
self.reg_scale = reg_scale
self.depth_mult = depth_mult
self.decoder_offset_scale = decoder_offset_scale
self.decoder_method = decoder_method
self.top_prob_values = top_prob_values
self.lqe_hidden_dim = lqe_hidden_dim
self.lqe_layers = lqe_layers
self.up = up
if isinstance(self.decoder_n_points, list):
if len(self.decoder_n_points) != self.num_feature_levels:
raise ValueError(
f"Length of decoder_n_points list ({len(self.decoder_n_points)}) must match num_feature_levels ({self.num_feature_levels})."
)
head_dim = self.d_model // self.decoder_attention_heads
if head_dim * self.decoder_attention_heads != self.d_model:
raise ValueError(
f"Embedded dimension {self.d_model} must be divisible by decoder_attention_heads {self.decoder_attention_heads}"
)
super().__init__(is_encoder_decoder=is_encoder_decoder, **kwargs)
@property
def num_attention_heads(self) -> int:
return self.encoder_attention_heads
@property
def hidden_size(self) -> int:
return self.d_model
@classmethod
def from_backbone_configs(cls, backbone_config: PretrainedConfig, **kwargs):
"""Instantiate a [`DFineConfig`] (or a derived class) from a pre-trained backbone model configuration and DETR model
configuration.
Args:
backbone_config ([`PretrainedConfig`]):
The backbone configuration.
Returns:
[`DFineConfig`]: An instance of a configuration object
"""
return cls(
backbone_config=backbone_config,
**kwargs,
)
__all__ = ["DFineConfig"]

View File

@@ -0,0 +1,688 @@
# coding=utf-8
# Copyright 2025 The HuggingFace Inc. team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
import json
import re
from pathlib import Path
import requests
import torch
from huggingface_hub import hf_hub_download
from PIL import Image
from torchvision import transforms
from transformers import DFineConfig, DFineForObjectDetection, RTDetrImageProcessor
from transformers.utils import logging
logging.set_verbosity_info()
logger = logging.get_logger(__name__)
def get_d_fine_config(model_name: str) -> DFineConfig:
config = DFineConfig()
config.num_labels = 80
repo_id = "huggingface/label-files"
filename = "object365-id2label.json" if "obj365" in model_name else "coco-detection-mmdet-id2label.json"
id2label = json.load(open(hf_hub_download(repo_id, filename, repo_type="dataset"), "r"))
id2label = {int(k): v for k, v in id2label.items()}
config.id2label = id2label
config.label2id = {v: k for k, v in id2label.items()}
config.backbone_config.hidden_sizes = [64, 128, 256, 512]
config.backbone_config.layer_type = "basic"
config.backbone_config.embedding_size = 32
config.hidden_expansion = 1.0
config.decoder_layers = 6
if model_name in ["dfine_x_coco", "dfine_x_obj2coco", "dfine_x_obj365"]:
config.backbone_config.hidden_sizes = [256, 512, 1024, 2048]
config.backbone_config.stage_in_channels = [64, 128, 512, 1024]
config.backbone_config.stage_mid_channels = [64, 128, 256, 512]
config.backbone_config.stage_out_channels = [128, 512, 1024, 2048]
config.backbone_config.stage_num_blocks = [1, 2, 5, 2]
config.backbone_config.stage_downsample = [False, True, True, True]
config.backbone_config.stage_light_block = [False, False, True, True]
config.backbone_config.stage_kernel_size = [3, 3, 5, 5]
config.backbone_config.stage_numb_of_layers = [6, 6, 6, 6]
config.backbone_config.stem_channels = [3, 32, 64]
config.encoder_in_channels = [512, 1024, 2048]
config.encoder_hidden_dim = 384
config.encoder_ffn_dim = 2048
config.decoder_n_points = [3, 6, 3]
config.decoder_in_channels = [384, 384, 384]
if model_name == "dfine_x_obj365":
config.num_labels = 366
elif model_name in ["dfine_m_coco", "dfine_m_obj2coco", "dfine_m_obj365"]:
config.backbone_config.hidden_sizes = [192, 384, 768, 1536]
config.backbone_config.stem_channels = [3, 24, 32]
config.backbone_config.stage_in_channels = [32, 96, 384, 768]
config.backbone_config.stage_mid_channels = [32, 64, 128, 256]
config.backbone_config.stage_out_channels = [96, 384, 768, 1536]
config.backbone_config.stage_num_blocks = [1, 1, 3, 1]
config.backbone_config.stage_downsample = [False, True, True, True]
config.backbone_config.stage_light_block = [False, False, True, True]
config.backbone_config.stage_kernel_size = [3, 3, 5, 5]
config.backbone_config.stage_numb_of_layers = [4, 4, 4, 4]
config.decoder_layers = 4
config.decoder_n_points = [3, 6, 3]
config.encoder_in_channels = [384, 768, 1536]
config.backbone_config.use_learnable_affine_block = True
config.depth_mult = 0.67
if model_name == "dfine_m_obj365":
config.num_labels = 366
elif model_name in ["dfine_l_coco", "dfine_l_obj2coco_e25", "dfine_l_obj365"]:
config.backbone_config.hidden_sizes = [256, 512, 1024, 2048]
config.backbone_config.stem_channels = [3, 32, 48]
config.backbone_config.stage_in_channels = [48, 128, 512, 1024]
config.backbone_config.stage_mid_channels = [48, 96, 192, 384]
config.backbone_config.stage_out_channels = [128, 512, 1024, 2048]
config.backbone_config.stage_num_blocks = [1, 1, 3, 1]
config.backbone_config.stage_downsample = [False, True, True, True]
config.backbone_config.stage_light_block = [False, False, True, True]
config.backbone_config.stage_kernel_size = [3, 3, 5, 5]
config.backbone_config.stage_numb_of_layers = [6, 6, 6, 6]
config.encoder_ffn_dim = 1024
config.encoder_in_channels = [512, 1024, 2048]
config.decoder_n_points = [3, 6, 3]
if model_name == "dfine_l_obj365":
config.num_labels = 366
elif model_name in ["dfine_n_coco", "dfine_n_obj2coco_e25", "dfine_n_obj365"]:
config.backbone_config.hidden_sizes = [128, 256, 512, 1024]
config.backbone_config.stem_channels = [3, 16, 16]
config.backbone_config.stage_in_channels = [16, 64, 256, 512]
config.backbone_config.stage_mid_channels = [16, 32, 64, 128]
config.backbone_config.stage_out_channels = [64, 256, 512, 1024]
config.backbone_config.stage_num_blocks = [1, 1, 2, 1]
config.backbone_config.stage_downsample = [False, True, True, True]
config.backbone_config.stage_light_block = [False, False, True, True]
config.backbone_config.stage_kernel_size = [3, 3, 5, 5]
config.backbone_config.stage_numb_of_layers = [3, 3, 3, 3]
config.backbone_config.out_indices = [3, 4]
config.backbone_config.use_learnable_affine_block = True
config.num_feature_levels = 2
config.encoder_ffn_dim = 512
config.encode_proj_layers = [1]
config.d_model = 128
config.encoder_hidden_dim = 128
config.decoder_ffn_dim = 512
config.encoder_in_channels = [512, 1024]
config.decoder_n_points = [6, 6]
config.decoder_in_channels = [128, 128]
config.feat_strides = [16, 32]
config.depth_mult = 0.5
config.decoder_layers = 3
config.hidden_expansion = 0.34
if model_name == "dfine_n_obj365":
config.num_labels = 366
else:
config.backbone_config.hidden_sizes = [128, 256, 512, 1024]
config.backbone_config.stem_channels = [3, 16, 16]
config.backbone_config.stage_in_channels = [16, 64, 256, 512]
config.backbone_config.stage_mid_channels = [16, 32, 64, 128]
config.backbone_config.stage_out_channels = [64, 256, 512, 1024]
config.backbone_config.stage_num_blocks = [1, 1, 2, 1]
config.backbone_config.stage_downsample = [False, True, True, True]
config.backbone_config.stage_light_block = [False, False, True, True]
config.backbone_config.stage_kernel_size = [3, 3, 5, 5]
config.backbone_config.stage_numb_of_layers = [3, 3, 3, 3]
config.decoder_layers = 3
config.hidden_expansion = 0.5
config.depth_mult = 0.34
config.decoder_n_points = [3, 6, 3]
config.encoder_in_channels = [256, 512, 1024]
config.backbone_config.use_learnable_affine_block = True
if model_name == "dfine_s_obj365":
config.num_labels = 366
return config
def load_original_state_dict(repo_id, model_name):
directory_path = hf_hub_download(repo_id=repo_id, filename=f"{model_name}.pth")
original_state_dict = {}
model = torch.load(directory_path, map_location="cpu")["model"]
for key in model.keys():
original_state_dict[key] = model[key]
return original_state_dict
ORIGINAL_TO_CONVERTED_KEY_MAPPING = {
# Decoder base mappings
r"decoder.valid_mask": r"model.decoder.valid_mask",
r"decoder.anchors": r"model.decoder.anchors",
r"decoder.up": r"model.decoder.up",
r"decoder.reg_scale": r"model.decoder.reg_scale",
# Backbone stem mappings - including stem2a and stem2b
r"backbone.stem.stem1.conv.weight": r"model.backbone.model.embedder.stem1.convolution.weight",
r"backbone.stem.stem2a.conv.weight": r"model.backbone.model.embedder.stem2a.convolution.weight",
r"backbone.stem.stem2b.conv.weight": r"model.backbone.model.embedder.stem2b.convolution.weight",
r"backbone.stem.stem3.conv.weight": r"model.backbone.model.embedder.stem3.convolution.weight",
r"backbone.stem.stem4.conv.weight": r"model.backbone.model.embedder.stem4.convolution.weight",
# Stem normalization
r"backbone.stem.stem1.bn.(weight|bias|running_mean|running_var)": r"model.backbone.model.embedder.stem1.normalization.\1",
r"backbone.stem.stem2a.bn.(weight|bias|running_mean|running_var)": r"model.backbone.model.embedder.stem2a.normalization.\1",
r"backbone.stem.stem2b.bn.(weight|bias|running_mean|running_var)": r"model.backbone.model.embedder.stem2b.normalization.\1",
r"backbone.stem.stem3.bn.(weight|bias|running_mean|running_var)": r"model.backbone.model.embedder.stem3.normalization.\1",
r"backbone.stem.stem4.bn.(weight|bias|running_mean|running_var)": r"model.backbone.model.embedder.stem4.normalization.\1",
# Stem lab parameters - fixed with .lab in the path
r"backbone.stem.stem1.lab.(scale|bias)": r"model.backbone.model.embedder.stem1.lab.\1",
r"backbone.stem.stem2a.lab.(scale|bias)": r"model.backbone.model.embedder.stem2a.lab.\1",
r"backbone.stem.stem2b.lab.(scale|bias)": r"model.backbone.model.embedder.stem2b.lab.\1",
r"backbone.stem.stem3.lab.(scale|bias)": r"model.backbone.model.embedder.stem3.lab.\1",
r"backbone.stem.stem4.lab.(scale|bias)": r"model.backbone.model.embedder.stem4.lab.\1",
# Backbone stages mappings
r"backbone.stages.(\d+).blocks.(\d+).layers.(\d+).conv.weight": r"model.backbone.model.encoder.stages.\1.blocks.\2.layers.\3.convolution.weight",
r"backbone.stages.(\d+).blocks.(\d+).layers.(\d+).bn.(weight|bias|running_mean|running_var)": r"model.backbone.model.encoder.stages.\1.blocks.\2.layers.\3.normalization.\4",
r"backbone.stages.(\d+).blocks.(\d+).layers.(\d+).conv1.conv.weight": r"model.backbone.model.encoder.stages.\1.blocks.\2.layers.\3.conv1.convolution.weight",
r"backbone.stages.(\d+).blocks.(\d+).layers.(\d+).conv2.conv.weight": r"model.backbone.model.encoder.stages.\1.blocks.\2.layers.\3.conv2.convolution.weight",
r"backbone.stages.(\d+).blocks.(\d+).layers.(\d+).conv1.bn.(weight|bias|running_mean|running_var)": r"model.backbone.model.encoder.stages.\1.blocks.\2.layers.\3.conv1.normalization.\4",
r"backbone.stages.(\d+).blocks.(\d+).layers.(\d+).conv2.bn.(weight|bias|running_mean|running_var)": r"model.backbone.model.encoder.stages.\1.blocks.\2.layers.\3.conv2.normalization.\4",
# Backbone stages aggregation
r"backbone.stages.(\d+).blocks.(\d+).aggregation.0.conv.weight": r"model.backbone.model.encoder.stages.\1.blocks.\2.aggregation.0.convolution.weight",
r"backbone.stages.(\d+).blocks.(\d+).aggregation.1.conv.weight": r"model.backbone.model.encoder.stages.\1.blocks.\2.aggregation.1.convolution.weight",
r"backbone.stages.(\d+).blocks.(\d+).aggregation.0.bn.(weight|bias|running_mean|running_var)": r"model.backbone.model.encoder.stages.\1.blocks.\2.aggregation.0.normalization.\3",
r"backbone.stages.(\d+).blocks.(\d+).aggregation.1.bn.(weight|bias|running_mean|running_var)": r"model.backbone.model.encoder.stages.\1.blocks.\2.aggregation.1.normalization.\3",
# Backbone stages lab parameters for aggregation
r"backbone.stages.(\d+).blocks.(\d+).aggregation.0.lab.(scale|bias)": r"model.backbone.model.encoder.stages.\1.blocks.\2.aggregation.0.lab.\3",
r"backbone.stages.(\d+).blocks.(\d+).aggregation.1.lab.(scale|bias)": r"model.backbone.model.encoder.stages.\1.blocks.\2.aggregation.1.lab.\3",
r"backbone.stages.(\d+).blocks.(\d+).layers.(\d+).lab.(scale|bias)": r"model.backbone.model.encoder.stages.\1.blocks.\2.layers.\3.lab.\4",
# Conv1/Conv2 layers with lab
r"backbone.stages.(\d+).blocks.(\d+).layers.(\d+).conv1.lab.(scale|bias)": r"model.backbone.model.encoder.stages.\1.blocks.\2.layers.\3.conv1.lab.\4",
r"backbone.stages.(\d+).blocks.(\d+).layers.(\d+).conv2.lab.(scale|bias)": r"model.backbone.model.encoder.stages.\1.blocks.\2.layers.\3.conv2.lab.\4",
# Downsample with lab
r"backbone.stages.(\d+).downsample.lab.(scale|bias)": r"model.backbone.model.encoder.stages.\1.downsample.lab.\2",
# Backbone downsample
r"backbone.stages.(\d+).downsample.conv.weight": r"model.backbone.model.encoder.stages.\1.downsample.convolution.weight",
r"backbone.stages.(\d+).downsample.bn.(weight|bias|running_mean|running_var)": r"model.backbone.model.encoder.stages.\1.downsample.normalization.\2",
# Encoder mappings
r"encoder.encoder.(\d+).layers.0.self_attn.out_proj.(weight|bias)": r"model.encoder.encoder.\1.layers.0.self_attn.out_proj.\2",
r"encoder.encoder.(\d+).layers.0.linear1.(weight|bias)": r"model.encoder.encoder.\1.layers.0.fc1.\2",
r"encoder.encoder.(\d+).layers.0.linear2.(weight|bias)": r"model.encoder.encoder.\1.layers.0.fc2.\2",
r"encoder.encoder.(\d+).layers.0.norm1.(weight|bias)": r"model.encoder.encoder.\1.layers.0.self_attn_layer_norm.\2",
r"encoder.encoder.(\d+).layers.0.norm2.(weight|bias)": r"model.encoder.encoder.\1.layers.0.final_layer_norm.\2",
# Encoder projections and convolutions
r"encoder.input_proj.(\d+).conv.weight": r"model.encoder_input_proj.\1.0.weight",
r"encoder.input_proj.(\d+).norm.(weight|bias|running_mean|running_var)": r"model.encoder_input_proj.\1.1.\2",
r"encoder.lateral_convs.(\d+).conv.weight": r"model.encoder.lateral_convs.\1.conv.weight",
r"encoder.lateral_convs.(\d+).norm.(weight|bias|running_mean|running_var)": r"model.encoder.lateral_convs.\1.norm.\2",
# FPN blocks - complete structure
# Basic convolutions
r"encoder.fpn_blocks.(\d+).cv1.conv.weight": r"model.encoder.fpn_blocks.\1.conv1.conv.weight",
r"encoder.fpn_blocks.(\d+).cv1.norm.(weight|bias|running_mean|running_var)": r"model.encoder.fpn_blocks.\1.conv1.norm.\2",
# CSP Rep1 path
r"encoder.fpn_blocks.(\d+).cv2.0.conv1.conv.weight": r"model.encoder.fpn_blocks.\1.csp_rep1.conv1.conv.weight",
r"encoder.fpn_blocks.(\d+).cv2.0.conv1.norm.(weight|bias|running_mean|running_var)": r"model.encoder.fpn_blocks.\1.csp_rep1.conv1.norm.\2",
r"encoder.fpn_blocks.(\d+).cv2.0.conv2.conv.weight": r"model.encoder.fpn_blocks.\1.csp_rep1.conv2.conv.weight",
r"encoder.fpn_blocks.(\d+).cv2.0.conv2.norm.(weight|bias|running_mean|running_var)": r"model.encoder.fpn_blocks.\1.csp_rep1.conv2.norm.\2",
r"encoder.fpn_blocks.(\d+).cv2.1.conv.weight": r"model.encoder.fpn_blocks.\1.conv2.conv.weight",
r"encoder.fpn_blocks.(\d+).cv2.1.norm.(weight|bias|running_mean|running_var)": r"model.encoder.fpn_blocks.\1.conv2.norm.\2",
# CSP Rep2 path
r"encoder.fpn_blocks.(\d+).cv3.0.conv1.conv.weight": r"model.encoder.fpn_blocks.\1.csp_rep2.conv1.conv.weight",
r"encoder.fpn_blocks.(\d+).cv3.0.conv1.norm.(weight|bias|running_mean|running_var)": r"model.encoder.fpn_blocks.\1.csp_rep2.conv1.norm.\2",
r"encoder.fpn_blocks.(\d+).cv3.0.conv2.conv.weight": r"model.encoder.fpn_blocks.\1.csp_rep2.conv2.conv.weight",
r"encoder.fpn_blocks.(\d+).cv3.0.conv2.norm.(weight|bias|running_mean|running_var)": r"model.encoder.fpn_blocks.\1.csp_rep2.conv2.norm.\2",
r"encoder.fpn_blocks.(\d+).cv3.1.conv.weight": r"model.encoder.fpn_blocks.\1.conv3.conv.weight",
r"encoder.fpn_blocks.(\d+).cv3.1.norm.(weight|bias|running_mean|running_var)": r"model.encoder.fpn_blocks.\1.conv3.norm.\2",
# Final conv
r"encoder.fpn_blocks.(\d+).cv4.conv.weight": r"model.encoder.fpn_blocks.\1.conv4.conv.weight",
r"encoder.fpn_blocks.(\d+).cv4.norm.(weight|bias|running_mean|running_var)": r"model.encoder.fpn_blocks.\1.conv4.norm.\2",
# Bottlenecks for CSP Rep1
r"encoder.fpn_blocks.(\d+).cv2.0.bottlenecks.(\d+).conv1.conv.weight": r"model.encoder.fpn_blocks.\1.csp_rep1.bottlenecks.\2.conv1.conv.weight",
r"encoder.fpn_blocks.(\d+).cv2.0.bottlenecks.(\d+).conv1.norm.(weight|bias|running_mean|running_var)": r"model.encoder.fpn_blocks.\1.csp_rep1.bottlenecks.\2.conv1.norm.\3",
r"encoder.fpn_blocks.(\d+).cv2.0.bottlenecks.(\d+).conv2.conv.weight": r"model.encoder.fpn_blocks.\1.csp_rep1.bottlenecks.\2.conv2.conv.weight",
r"encoder.fpn_blocks.(\d+).cv2.0.bottlenecks.(\d+).conv2.norm.(weight|bias|running_mean|running_var)": r"model.encoder.fpn_blocks.\1.csp_rep1.bottlenecks.\2.conv2.norm.\3",
# Bottlenecks for CSP Rep2
r"encoder.fpn_blocks.(\d+).cv3.0.bottlenecks.(\d+).conv1.conv.weight": r"model.encoder.fpn_blocks.\1.csp_rep2.bottlenecks.\2.conv1.conv.weight",
r"encoder.fpn_blocks.(\d+).cv3.0.bottlenecks.(\d+).conv1.norm.(weight|bias|running_mean|running_var)": r"model.encoder.fpn_blocks.\1.csp_rep2.bottlenecks.\2.conv1.norm.\3",
r"encoder.fpn_blocks.(\d+).cv3.0.bottlenecks.(\d+).conv2.conv.weight": r"model.encoder.fpn_blocks.\1.csp_rep2.bottlenecks.\2.conv2.conv.weight",
r"encoder.fpn_blocks.(\d+).cv3.0.bottlenecks.(\d+).conv2.norm.(weight|bias|running_mean|running_var)": r"model.encoder.fpn_blocks.\1.csp_rep2.bottlenecks.\2.conv2.norm.\3",
# PAN blocks - complete structure
# Basic convolutions
r"encoder.pan_blocks.(\d+).cv1.conv.weight": r"model.encoder.pan_blocks.\1.conv1.conv.weight",
r"encoder.pan_blocks.(\d+).cv1.norm.(weight|bias|running_mean|running_var)": r"model.encoder.pan_blocks.\1.conv1.norm.\2",
# CSP Rep1 path
r"encoder.pan_blocks.(\d+).cv2.0.conv1.conv.weight": r"model.encoder.pan_blocks.\1.csp_rep1.conv1.conv.weight",
r"encoder.pan_blocks.(\d+).cv2.0.conv1.norm.(weight|bias|running_mean|running_var)": r"model.encoder.pan_blocks.\1.csp_rep1.conv1.norm.\2",
r"encoder.pan_blocks.(\d+).cv2.0.conv2.conv.weight": r"model.encoder.pan_blocks.\1.csp_rep1.conv2.conv.weight",
r"encoder.pan_blocks.(\d+).cv2.0.conv2.norm.(weight|bias|running_mean|running_var)": r"model.encoder.pan_blocks.\1.csp_rep1.conv2.norm.\2",
r"encoder.pan_blocks.(\d+).cv2.1.conv.weight": r"model.encoder.pan_blocks.\1.conv2.conv.weight",
r"encoder.pan_blocks.(\d+).cv2.1.norm.(weight|bias|running_mean|running_var)": r"model.encoder.pan_blocks.\1.conv2.norm.\2",
# CSP Rep2 path
r"encoder.pan_blocks.(\d+).cv3.0.conv1.conv.weight": r"model.encoder.pan_blocks.\1.csp_rep2.conv1.conv.weight",
r"encoder.pan_blocks.(\d+).cv3.0.conv1.norm.(weight|bias|running_mean|running_var)": r"model.encoder.pan_blocks.\1.csp_rep2.conv1.norm.\2",
r"encoder.pan_blocks.(\d+).cv3.0.conv2.conv.weight": r"model.encoder.pan_blocks.\1.csp_rep2.conv2.conv.weight",
r"encoder.pan_blocks.(\d+).cv3.0.conv2.norm.(weight|bias|running_mean|running_var)": r"model.encoder.pan_blocks.\1.csp_rep2.conv2.norm.\2",
r"encoder.pan_blocks.(\d+).cv3.1.conv.weight": r"model.encoder.pan_blocks.\1.conv3.conv.weight",
r"encoder.pan_blocks.(\d+).cv3.1.norm.(weight|bias|running_mean|running_var)": r"model.encoder.pan_blocks.\1.conv3.norm.\2",
# Final conv
r"encoder.pan_blocks.(\d+).cv4.conv.weight": r"model.encoder.pan_blocks.\1.conv4.conv.weight",
r"encoder.pan_blocks.(\d+).cv4.norm.(weight|bias|running_mean|running_var)": r"model.encoder.pan_blocks.\1.conv4.norm.\2",
# Bottlenecks for CSP Rep1
r"encoder.pan_blocks.(\d+).cv2.0.bottlenecks.(\d+).conv1.conv.weight": r"model.encoder.pan_blocks.\1.csp_rep1.bottlenecks.\2.conv1.conv.weight",
r"encoder.pan_blocks.(\d+).cv2.0.bottlenecks.(\d+).conv1.norm.(weight|bias|running_mean|running_var)": r"model.encoder.pan_blocks.\1.csp_rep1.bottlenecks.\2.conv1.norm.\3",
r"encoder.pan_blocks.(\d+).cv2.0.bottlenecks.(\d+).conv2.conv.weight": r"model.encoder.pan_blocks.\1.csp_rep1.bottlenecks.\2.conv2.conv.weight",
r"encoder.pan_blocks.(\d+).cv2.0.bottlenecks.(\d+).conv2.norm.(weight|bias|running_mean|running_var)": r"model.encoder.pan_blocks.\1.csp_rep1.bottlenecks.\2.conv2.norm.\3",
# Bottlenecks for CSP Rep2
r"encoder.pan_blocks.(\d+).cv3.0.bottlenecks.(\d+).conv1.conv.weight": r"model.encoder.pan_blocks.\1.csp_rep2.bottlenecks.\2.conv1.conv.weight",
r"encoder.pan_blocks.(\d+).cv3.0.bottlenecks.(\d+).conv1.norm.(weight|bias|running_mean|running_var)": r"model.encoder.pan_blocks.\1.csp_rep2.bottlenecks.\2.conv1.norm.\3",
r"encoder.pan_blocks.(\d+).cv3.0.bottlenecks.(\d+).conv2.conv.weight": r"model.encoder.pan_blocks.\1.csp_rep2.bottlenecks.\2.conv2.conv.weight",
r"encoder.pan_blocks.(\d+).cv3.0.bottlenecks.(\d+).conv2.norm.(weight|bias|running_mean|running_var)": r"model.encoder.pan_blocks.\1.csp_rep2.bottlenecks.\2.conv2.norm.\3",
# Downsample convolutions
r"encoder.downsample_convs.(\d+).0.cv(\d+).conv.weight": r"model.encoder.downsample_convs.\1.conv\2.conv.weight",
r"encoder.downsample_convs.(\d+).0.cv(\d+).norm.(weight|bias|running_mean|running_var)": r"model.encoder.downsample_convs.\1.conv\2.norm.\3",
# Decoder layers
r"decoder.decoder.layers.(\d+).self_attn.out_proj.(weight|bias)": r"model.decoder.layers.\1.self_attn.out_proj.\2",
r"decoder.decoder.layers.(\d+).cross_attn.sampling_offsets.(weight|bias)": r"model.decoder.layers.\1.encoder_attn.sampling_offsets.\2",
r"decoder.decoder.layers.(\d+).cross_attn.attention_weights.(weight|bias)": r"model.decoder.layers.\1.encoder_attn.attention_weights.\2",
r"decoder.decoder.layers.(\d+).cross_attn.value_proj.(weight|bias)": r"model.decoder.layers.\1.encoder_attn.value_proj.\2",
r"decoder.decoder.layers.(\d+).cross_attn.output_proj.(weight|bias)": r"model.decoder.layers.\1.encoder_attn.output_proj.\2",
r"decoder.decoder.layers.(\d+).cross_attn.num_points_scale": r"model.decoder.layers.\1.encoder_attn.num_points_scale",
r"decoder.decoder.layers.(\d+).gateway.gate.(weight|bias)": r"model.decoder.layers.\1.gateway.gate.\2",
r"decoder.decoder.layers.(\d+).gateway.norm.(weight|bias)": r"model.decoder.layers.\1.gateway.norm.\2",
r"decoder.decoder.layers.(\d+).norm1.(weight|bias)": r"model.decoder.layers.\1.self_attn_layer_norm.\2",
r"decoder.decoder.layers.(\d+).norm2.(weight|bias)": r"model.decoder.layers.\1.encoder_attn_layer_norm.\2",
r"decoder.decoder.layers.(\d+).norm3.(weight|bias)": r"model.decoder.layers.\1.final_layer_norm.\2",
r"decoder.decoder.layers.(\d+).linear1.(weight|bias)": r"model.decoder.layers.\1.fc1.\2",
r"decoder.decoder.layers.(\d+).linear2.(weight|bias)": r"model.decoder.layers.\1.fc2.\2",
# LQE layers
r"decoder.decoder.lqe_layers.(\d+).reg_conf.layers.(\d+).(weight|bias)": r"model.decoder.lqe_layers.\1.reg_conf.layers.\2.\3",
# Decoder heads and projections
r"decoder.dec_score_head.(\d+).(weight|bias)": r"model.decoder.class_embed.\1.\2",
r"decoder.dec_bbox_head.(\d+).layers.(\d+).(weight|bias)": r"model.decoder.bbox_embed.\1.layers.\2.\3",
r"decoder.pre_bbox_head.layers.(\d+).(weight|bias)": r"model.decoder.pre_bbox_head.layers.\1.\2",
r"decoder.input_proj.(\d+).conv.weight": r"model.decoder_input_proj.\1.0.weight",
r"decoder.input_proj.(\d+).norm.(weight|bias|running_mean|running_var)": r"model.decoder_input_proj.\1.1.\2",
# Other decoder components
r"decoder.denoising_class_embed.weight": r"model.denoising_class_embed.weight",
r"decoder.query_pos_head.layers.(\d+).(weight|bias)": r"model.decoder.query_pos_head.layers.\1.\2",
r"decoder.enc_output.proj.(weight|bias)": r"model.enc_output.0.\1",
r"decoder.enc_output.norm.(weight|bias)": r"model.enc_output.1.\1",
r"decoder.enc_score_head.(weight|bias)": r"model.enc_score_head.\1",
r"decoder.enc_bbox_head.layers.(\d+).(weight|bias)": r"model.enc_bbox_head.layers.\1.\2",
}
def convert_old_keys_to_new_keys(state_dict_keys: dict = None):
# Use the mapping to rename keys
for original_key, converted_key in ORIGINAL_TO_CONVERTED_KEY_MAPPING.items():
for key in list(state_dict_keys.keys()):
new_key = re.sub(original_key, converted_key, key)
if new_key != key:
state_dict_keys[new_key] = state_dict_keys.pop(key)
return state_dict_keys
def read_in_q_k_v(state_dict, config, model_name):
prefix = ""
encoder_hidden_dim = config.encoder_hidden_dim
# first: transformer encoder
for i in range(config.encoder_layers):
# read in weights + bias of input projection layer (in PyTorch's MultiHeadAttention, this is a single matrix + bias)
in_proj_weight = state_dict.pop(f"{prefix}encoder.encoder.{i}.layers.0.self_attn.in_proj_weight")
in_proj_bias = state_dict.pop(f"{prefix}encoder.encoder.{i}.layers.0.self_attn.in_proj_bias")
# next, add query, keys and values (in that order) to the state dict
state_dict[f"model.encoder.encoder.{i}.layers.0.self_attn.q_proj.weight"] = in_proj_weight[
:encoder_hidden_dim, :
]
state_dict[f"model.encoder.encoder.{i}.layers.0.self_attn.q_proj.bias"] = in_proj_bias[:encoder_hidden_dim]
state_dict[f"model.encoder.encoder.{i}.layers.0.self_attn.k_proj.weight"] = in_proj_weight[
encoder_hidden_dim : 2 * encoder_hidden_dim, :
]
state_dict[f"model.encoder.encoder.{i}.layers.0.self_attn.k_proj.bias"] = in_proj_bias[
encoder_hidden_dim : 2 * encoder_hidden_dim
]
state_dict[f"model.encoder.encoder.{i}.layers.0.self_attn.v_proj.weight"] = in_proj_weight[
-encoder_hidden_dim:, :
]
state_dict[f"model.encoder.encoder.{i}.layers.0.self_attn.v_proj.bias"] = in_proj_bias[-encoder_hidden_dim:]
# next: transformer decoder (which is a bit more complex because it also includes cross-attention)
for i in range(config.decoder_layers):
# read in weights + bias of input projection layer of self-attention
in_proj_weight = state_dict.pop(f"{prefix}decoder.decoder.layers.{i}.self_attn.in_proj_weight", None)
in_proj_bias = state_dict.pop(f"{prefix}decoder.decoder.layers.{i}.self_attn.in_proj_bias", None)
# next, add query, keys and values (in that order) to the state dict
if model_name in ["dfine_n_coco", "dfine_n_obj2coco_e25", "dfine_n_obj365"]:
state_dict[f"model.decoder.layers.{i}.self_attn.q_proj.weight"] = in_proj_weight[:128, :]
state_dict[f"model.decoder.layers.{i}.self_attn.q_proj.bias"] = in_proj_bias[:128]
state_dict[f"model.decoder.layers.{i}.self_attn.k_proj.weight"] = in_proj_weight[256:384, :]
state_dict[f"model.decoder.layers.{i}.self_attn.k_proj.bias"] = in_proj_bias[256:384]
state_dict[f"model.decoder.layers.{i}.self_attn.v_proj.weight"] = in_proj_weight[-128:, :]
state_dict[f"model.decoder.layers.{i}.self_attn.v_proj.bias"] = in_proj_bias[-128:]
else:
state_dict[f"model.decoder.layers.{i}.self_attn.q_proj.weight"] = in_proj_weight[:256, :]
state_dict[f"model.decoder.layers.{i}.self_attn.q_proj.bias"] = in_proj_bias[:256]
state_dict[f"model.decoder.layers.{i}.self_attn.k_proj.weight"] = in_proj_weight[256:512, :]
state_dict[f"model.decoder.layers.{i}.self_attn.k_proj.bias"] = in_proj_bias[256:512]
state_dict[f"model.decoder.layers.{i}.self_attn.v_proj.weight"] = in_proj_weight[-256:, :]
state_dict[f"model.decoder.layers.{i}.self_attn.v_proj.bias"] = in_proj_bias[-256:]
# We will verify our results on an image of cute cats
def prepare_img():
url = "http://images.cocodataset.org/val2017/000000039769.jpg"
im = Image.open(requests.get(url, stream=True).raw)
return im
@torch.no_grad()
def convert_d_fine_checkpoint(model_name, pytorch_dump_folder_path, push_to_hub, repo_id):
"""
Copy/paste/tweak model's weights to our D-FINE structure.
"""
# load default config
config = get_d_fine_config(model_name)
state_dict = load_original_state_dict(repo_id, model_name)
state_dict.pop("decoder.valid_mask", None)
state_dict.pop("decoder.anchors", None)
model = DFineForObjectDetection(config)
logger.info(f"Converting model {model_name}...")
state_dict = convert_old_keys_to_new_keys(state_dict)
state_dict.pop("decoder.model.decoder.up", None)
state_dict.pop("decoder.model.decoder.reg_scale", None)
# query, key and value matrices need special treatment
read_in_q_k_v(state_dict, config, model_name)
# important: we need to prepend a prefix to each of the base model keys as the head models use different attributes for them
for key in state_dict.copy().keys():
if key.endswith("num_batches_tracked"):
del state_dict[key]
# for two_stage
if "bbox_embed" in key or ("class_embed" in key and "denoising_" not in key):
state_dict[key.split("model.decoder.")[-1]] = state_dict[key]
# finally, create HuggingFace model and load state dict
model.load_state_dict(state_dict)
model.eval()
# load image processor
image_processor = RTDetrImageProcessor()
# prepare image
img = prepare_img()
# preprocess image
transformations = transforms.Compose(
[
transforms.Resize([640, 640], interpolation=transforms.InterpolationMode.BILINEAR),
transforms.ToTensor(),
]
)
original_pixel_values = transformations(img).unsqueeze(0) # insert batch dimension
encoding = image_processor(images=img, return_tensors="pt")
pixel_values = encoding["pixel_values"]
assert torch.allclose(original_pixel_values, pixel_values)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)
pixel_values = pixel_values.to(device)
outputs = model(pixel_values)
if model_name == "dfine_x_coco":
expected_slice_logits = torch.tensor(
[
[-4.844723, -4.7293096, -4.5971327],
[-4.554266, -4.61723, -4.627926],
[-4.3934402, -4.6064143, -4.139952],
]
)
expected_slice_boxes = torch.tensor(
[
[0.2565248, 0.5477609, 0.47644863],
[0.7690029, 0.41423926, 0.46148556],
[0.1688096, 0.19923759, 0.21118002],
]
)
elif model_name == "dfine_x_obj2coco":
expected_slice_logits = torch.tensor(
[
[-4.230433, -6.6295037, -4.8339615],
[-4.085411, -6.3280816, -4.695468],
[-3.8968022, -6.336813, -4.67051],
]
)
expected_slice_boxes = torch.tensor(
[
[0.25707328, 0.54842496, 0.47624254],
[0.76967394, 0.41272867, 0.45970756],
[0.16882066, 0.19918433, 0.2112098],
]
)
elif model_name == "dfine_x_obj365":
expected_slice_logits = torch.tensor(
[
[-6.3844957, -3.7549126, -4.6873264],
[-5.8433194, -3.4490552, -3.3228905],
[-6.5314736, -3.7856622, -4.895984],
]
)
expected_slice_boxes = torch.tensor(
[
[0.7703046, 0.41329497, 0.45932162],
[0.16898105, 0.19876392, 0.21050783],
[0.25134972, 0.5517619, 0.4864124],
]
)
elif model_name == "dfine_m_coco":
expected_slice_logits = torch.tensor(
[
[-4.5187078, -4.71708, -4.117749],
[-4.513984, -4.937715, -3.829125],
[-4.830042, -6.931682, -3.1740026],
]
)
expected_slice_boxes = torch.tensor(
[
[0.25851426, 0.5489963, 0.4757598],
[0.769683, 0.41411665, 0.45988125],
[0.16866133, 0.19921188, 0.21207744],
]
)
elif model_name == "dfine_m_obj2coco":
expected_slice_logits = torch.tensor(
[
[-4.520666, -7.6678333, -5.739887],
[-4.5053635, -7.510611, -5.452532],
[-4.70348, -5.6098466, -5.0199957],
]
)
expected_slice_boxes = torch.tensor(
[
[0.2567608, 0.5485795, 0.4767465],
[0.77035284, 0.41236404, 0.4580645],
[0.5498525, 0.27548885, 0.05886984],
]
)
elif model_name == "dfine_m_obj365":
expected_slice_logits = torch.tensor(
[
[-5.770525, -3.1610885, -5.2807794],
[-5.7809954, -3.768266, -5.1146393],
[-6.180705, -3.7357295, -3.1651964],
]
)
expected_slice_boxes = torch.tensor(
[
[0.2529114, 0.5526663, 0.48270613],
[0.7712474, 0.41294736, 0.457174],
[0.5497157, 0.27588123, 0.05813372],
]
)
elif model_name == "dfine_l_coco":
expected_slice_logits = torch.tensor(
[
[-4.068779, -5.169955, -4.339212],
[-3.9461594, -5.0279613, -4.0161457],
[-4.218292, -6.196324, -5.175245],
]
)
expected_slice_boxes = torch.tensor(
[
[0.2564867, 0.5489948, 0.4748876],
[0.7693534, 0.4138953, 0.4598034],
[0.16875696, 0.19875404, 0.21196914],
]
)
elif model_name == "dfine_l_obj365":
expected_slice_logits = torch.tensor(
[
[-5.7953215, -3.4901116, -5.4394145],
[-5.7032104, -3.671125, -5.76121],
[-6.09466, -3.1512096, -4.285499],
]
)
expected_slice_boxes = torch.tensor(
[
[0.7693825, 0.41265628, 0.4606362],
[0.25306237, 0.55187637, 0.4832178],
[0.16892478, 0.19880727, 0.21115331],
]
)
elif model_name == "dfine_l_obj2coco_e25":
expected_slice_logits = torch.tensor(
[
[-3.6098495, -6.633563, -5.1227236],
[-3.682696, -6.9178205, -5.414557],
[-4.491674, -6.0823426, -4.5718226],
]
)
expected_slice_boxes = torch.tensor(
[
[0.7697078, 0.41368833, 0.45879585],
[0.2573691, 0.54856044, 0.47715297],
[0.16895264, 0.19871138, 0.2115552],
]
)
elif model_name == "dfine_n_coco":
expected_slice_logits = torch.tensor(
[
[-3.7827945, -5.0889463, -4.8341026],
[-5.3046904, -6.2801714, -2.9276395],
[-4.497901, -5.2670407, -6.2380104],
]
)
expected_slice_boxes = torch.tensor(
[
[0.73334837, 0.4270624, 0.39424777],
[0.1680235, 0.1988639, 0.21031213],
[0.25370035, 0.5534435, 0.48496848],
]
)
elif model_name == "dfine_s_coco":
expected_slice_logits = torch.tensor(
[
[-3.8097816, -4.7724586, -5.994499],
[-5.2974715, -9.499067, -6.1653666],
[-5.3502765, -3.9530406, -6.3630295],
]
)
expected_slice_boxes = torch.tensor(
[
[0.7677696, 0.41479152, 0.46441072],
[0.16912134, 0.19869131, 0.2123824],
[0.2581653, 0.54818195, 0.47512347],
]
)
elif model_name == "dfine_s_obj2coco":
expected_slice_logits = torch.tensor(
[
[-6.0208125, -7.532673, -5.0572147],
[-3.3595953, -9.057545, -6.376975],
[-4.3203554, -9.546032, -6.075504],
]
)
expected_slice_boxes = torch.tensor(
[
[0.16901012, 0.19883151, 0.21121952],
[0.76784194, 0.41266578, 0.46402973],
[00.2563128, 0.54797643, 0.47937632],
]
)
elif model_name == "dfine_s_obj365":
expected_slice_logits = torch.tensor(
[
[-6.3807316, -4.320986, -6.4775343],
[-6.5818424, -3.5009093, -5.75824],
[-5.748005, -4.3228016, -4.003726],
]
)
expected_slice_boxes = torch.tensor(
[
[0.2532072, 0.5491191, 0.48222217],
[0.76586807, 0.41175705, 0.46789962],
[0.169111, 0.19844547, 0.21069047],
]
)
else:
raise ValueError(f"Unknown d_fine_name: {model_name}")
assert torch.allclose(outputs.logits[0, :3, :3], expected_slice_logits.to(outputs.logits.device), atol=1e-3)
assert torch.allclose(outputs.pred_boxes[0, :3, :3], expected_slice_boxes.to(outputs.pred_boxes.device), atol=1e-4)
if pytorch_dump_folder_path is not None:
Path(pytorch_dump_folder_path).mkdir(exist_ok=True)
print(f"Saving model {model_name} to {pytorch_dump_folder_path}")
model.save_pretrained(pytorch_dump_folder_path)
print(f"Saving image processor to {pytorch_dump_folder_path}")
image_processor.save_pretrained(pytorch_dump_folder_path)
if push_to_hub:
# Upload model, image processor and config to the hub
logger.info("Uploading PyTorch model and image processor to the hub...")
config.push_to_hub(
repo_id=repo_id,
commit_message="Add config from convert_d_fine_original_pytorch_checkpoint_to_hf.py",
)
model.push_to_hub(
repo_id=repo_id,
commit_message="Add model from convert_d_fine_original_pytorch_checkpoint_to_hf.py",
)
image_processor.push_to_hub(
repo_id=repo_id,
commit_message="Add image processor from convert_d_fine_original_pytorch_checkpoint_to_hf.py",
)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
"--model_name",
default="dfine_s_coco",
type=str,
help="model_name of the checkpoint you'd like to convert.",
)
parser.add_argument(
"--pytorch_dump_folder_path", default=None, type=str, help="Path to the output PyTorch model directory."
)
parser.add_argument("--push_to_hub", action="store_true", help="Whether to push the model to the hub or not.")
parser.add_argument(
"--repo_id",
type=str,
help="repo_id where the model will be pushed to.",
)
args = parser.parse_args()
convert_d_fine_checkpoint(args.model_name, args.pytorch_dump_folder_path, args.push_to_hub, args.repo_id)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
# Copyright 2025 The HuggingFace Team. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import TYPE_CHECKING
from ...utils import _LazyModule
from ...utils.import_utils import define_import_structure
if TYPE_CHECKING:
from .configuration_hgnet_v2 import *
from .modeling_hgnet_v2 import *
else:
import sys
_file = globals()["__file__"]
sys.modules[__name__] = _LazyModule(__name__, _file, define_import_structure(_file), module_spec=__spec__)

View File

@@ -0,0 +1,152 @@
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
# This file was automatically generated from src/transformers/models/hgnet_v2/modular_hgnet_v2.py.
# Do NOT edit this file manually as any edits will be overwritten by the generation of
# the file from the modular. If any change should be done, please apply the change to the
# modular_hgnet_v2.py file directly. One of our CI enforces this.
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
# coding=utf-8
# Copyright 2025 Baidu Inc and The HuggingFace Inc. team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from ...configuration_utils import PretrainedConfig
from ...utils.backbone_utils import BackboneConfigMixin, get_aligned_output_features_output_indices
# TODO: Modular conversion for resnet must be fixed as
# it provides incorrect import for configuration like resnet_resnet
class HGNetV2Config(BackboneConfigMixin, PretrainedConfig):
"""
This is the configuration class to store the configuration of a [`HGNetV2Backbone`]. It is used to instantiate a HGNet-V2
model according to the specified arguments, defining the model architecture. Instantiating a configuration with the
defaults will yield a similar configuration to that of D-FINE-X-COCO B4 "[ustc-community/dfine_x_coco"](https://huggingface.co/ustc-community/dfine_x_coco").
Configuration objects inherit from [`PretrainedConfig`] and can be used to control the model outputs. Read the
documentation from [`PretrainedConfig`] for more information.
Args:
num_channels (`int`, *optional*, defaults to 3):
The number of input channels.
embedding_size (`int`, *optional*, defaults to 64):
Dimensionality (hidden size) for the embedding layer.
depths (`List[int]`, *optional*, defaults to `[3, 4, 6, 3]`):
Depth (number of layers) for each stage.
hidden_sizes (`List[int]`, *optional*, defaults to `[256, 512, 1024, 2048]`):
Dimensionality (hidden size) at each stage.
hidden_act (`str`, *optional*, defaults to `"relu"`):
The non-linear activation function in each block. If string, `"gelu"`, `"relu"`, `"selu"` and `"gelu_new"`
are supported.
out_features (`List[str]`, *optional*):
If used as backbone, list of features to output. Can be any of `"stem"`, `"stage1"`, `"stage2"`, etc.
(depending on how many stages the model has). If unset and `out_indices` is set, will default to the
corresponding stages. If unset and `out_indices` is unset, will default to the last stage. Must be in the
same order as defined in the `stage_names` attribute.
out_indices (`List[int]`, *optional*):
If used as backbone, list of indices of features to output. Can be any of 0, 1, 2, etc. (depending on how
many stages the model has). If unset and `out_features` is set, will default to the corresponding stages.
If unset and `out_features` is unset, will default to the last stage. Must be in the
same order as defined in the `stage_names` attribute.
stem_channels (`List[int]`, *optional*, defaults to `[3, 32, 48]`):
Channel dimensions for the stem layers:
- First number (3) is input image channels
- Second number (32) is intermediate stem channels
- Third number (48) is output stem channels
stage_in_channels (`List[int]`, *optional*, defaults to `[48, 128, 512, 1024]`):
Input channel dimensions for each stage of the backbone.
This defines how many channels the input to each stage will have.
stage_mid_channels (`List[int]`, *optional*, defaults to `[48, 96, 192, 384]`):
Mid-channel dimensions for each stage of the backbone.
This defines the number of channels used in the intermediate layers of each stage.
stage_out_channels (`List[int]`, *optional*, defaults to `[128, 512, 1024, 2048]`):
Output channel dimensions for each stage of the backbone.
This defines how many channels the output of each stage will have.
stage_num_blocks (`List[int]`, *optional*, defaults to `[1, 1, 3, 1]`):
Number of blocks to be used in each stage of the backbone.
This controls the depth of each stage by specifying how many convolutional blocks to stack.
stage_downsample (`List[bool]`, *optional*, defaults to `[False, True, True, True]`):
Indicates whether to downsample the feature maps at each stage.
If `True`, the spatial dimensions of the feature maps will be reduced.
stage_light_block (`List[bool]`, *optional*, defaults to `[False, False, True, True]`):
Indicates whether to use light blocks in each stage.
Light blocks are a variant of convolutional blocks that may have fewer parameters.
stage_kernel_size (`List[int]`, *optional*, defaults to `[3, 3, 5, 5]`):
Kernel sizes for the convolutional layers in each stage.
stage_numb_of_layers (`List[int]`, *optional*, defaults to `[6, 6, 6, 6]`):
Number of layers to be used in each block of the stage.
use_learnable_affine_block (`bool`, *optional*, defaults to `False`):
Whether to use Learnable Affine Blocks (LAB) in the network.
LAB adds learnable scale and bias parameters after certain operations.
initializer_range (`float`, *optional*, defaults to 0.02):
The standard deviation of the truncated_normal_initializer for initializing all weight matrices.
"""
model_type = "hgnet_v2"
def __init__(
self,
num_channels=3,
embedding_size=64,
depths=[3, 4, 6, 3],
hidden_sizes=[256, 512, 1024, 2048],
hidden_act="relu",
out_features=None,
out_indices=None,
stem_channels=[3, 32, 48],
stage_in_channels=[48, 128, 512, 1024],
stage_mid_channels=[48, 96, 192, 384],
stage_out_channels=[128, 512, 1024, 2048],
stage_num_blocks=[1, 1, 3, 1],
stage_downsample=[False, True, True, True],
stage_light_block=[False, False, True, True],
stage_kernel_size=[3, 3, 5, 5],
stage_numb_of_layers=[6, 6, 6, 6],
use_learnable_affine_block=False,
initializer_range=0.02,
**kwargs,
):
super().__init__(**kwargs)
self.num_channels = num_channels
self.embedding_size = embedding_size
self.depths = depths
self.hidden_sizes = hidden_sizes
self.hidden_act = hidden_act
self.stage_names = ["stem"] + [f"stage{idx}" for idx in range(1, len(depths) + 1)]
self._out_features, self._out_indices = get_aligned_output_features_output_indices(
out_features=out_features, out_indices=out_indices, stage_names=self.stage_names
)
self.stem_channels = stem_channels
self.stage_in_channels = stage_in_channels
self.stage_mid_channels = stage_mid_channels
self.stage_out_channels = stage_out_channels
self.stage_num_blocks = stage_num_blocks
self.stage_downsample = stage_downsample
self.stage_light_block = stage_light_block
self.stage_kernel_size = stage_kernel_size
self.stage_numb_of_layers = stage_numb_of_layers
self.use_learnable_affine_block = use_learnable_affine_block
self.initializer_range = initializer_range
if not (
len(stage_in_channels)
== len(stage_mid_channels)
== len(stage_out_channels)
== len(stage_num_blocks)
== len(stage_downsample)
== len(stage_light_block)
== len(stage_kernel_size)
== len(stage_numb_of_layers)
):
raise ValueError("All stage configuration lists must have the same length.")
__all__ = ["HGNetV2Config"]

View File

@@ -0,0 +1,541 @@
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
# This file was automatically generated from src/transformers/models/hgnet_v2/modular_hgnet_v2.py.
# Do NOT edit this file manually as any edits will be overwritten by the generation of
# the file from the modular. If any change should be done, please apply the change to the
# modular_hgnet_v2.py file directly. One of our CI enforces this.
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
# coding=utf-8
# Copyright 2025 Baidu Inc and The HuggingFace Inc. team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Optional
import torch
import torch.nn.functional as F
from torch import Tensor, nn
from torch.nn import BCEWithLogitsLoss, CrossEntropyLoss, MSELoss
from ...activations import ACT2FN
from ...modeling_outputs import BackboneOutput, BaseModelOutputWithNoAttention, ImageClassifierOutputWithNoAttention
from ...modeling_utils import PreTrainedModel
from ...utils import add_start_docstrings, add_start_docstrings_to_model_forward, replace_return_docstrings
from ...utils.backbone_utils import BackboneMixin
from .configuration_hgnet_v2 import HGNetV2Config
# General docstring
_CONFIG_FOR_DOC = "HGNetV2Config"
class HGNetV2PreTrainedModel(PreTrainedModel):
"""
An abstract class to handle weights initialization and a simple interface for downloading and loading pretrained
models.
"""
config_class = HGNetV2Config
base_model_prefix = "hgnetv2"
main_input_name = "pixel_values"
_no_split_modules = ["HGNetV2BasicLayer"]
def _init_weights(self, module):
if isinstance(module, (nn.Linear, nn.Conv2d)):
module.weight.data.normal_(mean=0.0, std=self.config.initializer_range)
if module.bias is not None:
module.bias.data.zero_()
elif isinstance(module, nn.BatchNorm2d):
module.weight.data.fill_(1.0)
if module.bias is not None:
module.bias.data.zero_()
class HGNetV2LearnableAffineBlock(nn.Module):
def __init__(self, scale_value: float = 1.0, bias_value: float = 0.0):
super().__init__()
self.scale = nn.Parameter(torch.tensor([scale_value]), requires_grad=True)
self.bias = nn.Parameter(torch.tensor([bias_value]), requires_grad=True)
def forward(self, hidden_state: Tensor) -> Tensor:
hidden_state = self.scale * hidden_state + self.bias
return hidden_state
class HGNetV2ConvLayer(nn.Module):
def __init__(
self,
in_channels: int,
out_channels: int,
kernel_size: int,
stride: int = 1,
groups: int = 1,
activation: str = "relu",
use_learnable_affine_block: bool = False,
):
super().__init__()
self.convolution = nn.Conv2d(
in_channels,
out_channels,
kernel_size=kernel_size,
stride=stride,
groups=groups,
padding=(kernel_size - 1) // 2,
bias=False,
)
self.normalization = nn.BatchNorm2d(out_channels)
self.activation = ACT2FN[activation] if activation is not None else nn.Identity()
if activation and use_learnable_affine_block:
self.lab = HGNetV2LearnableAffineBlock()
else:
self.lab = nn.Identity()
def forward(self, input: Tensor) -> Tensor:
hidden_state = self.convolution(input)
hidden_state = self.normalization(hidden_state)
hidden_state = self.activation(hidden_state)
hidden_state = self.lab(hidden_state)
return hidden_state
class HGNetV2ConvLayerLight(nn.Module):
def __init__(
self, in_channels: int, out_channels: int, kernel_size: int, use_learnable_affine_block: bool = False
):
super().__init__()
self.conv1 = HGNetV2ConvLayer(
in_channels,
out_channels,
kernel_size=1,
activation=None,
use_learnable_affine_block=use_learnable_affine_block,
)
self.conv2 = HGNetV2ConvLayer(
out_channels,
out_channels,
kernel_size=kernel_size,
groups=out_channels,
use_learnable_affine_block=use_learnable_affine_block,
)
def forward(self, hidden_state: Tensor) -> Tensor:
hidden_state = self.conv1(hidden_state)
hidden_state = self.conv2(hidden_state)
return hidden_state
class HGNetV2Embeddings(nn.Module):
def __init__(self, config: HGNetV2Config):
super().__init__()
self.stem1 = HGNetV2ConvLayer(
config.stem_channels[0],
config.stem_channels[1],
kernel_size=3,
stride=2,
activation=config.hidden_act,
use_learnable_affine_block=config.use_learnable_affine_block,
)
self.stem2a = HGNetV2ConvLayer(
config.stem_channels[1],
config.stem_channels[1] // 2,
kernel_size=2,
stride=1,
activation=config.hidden_act,
use_learnable_affine_block=config.use_learnable_affine_block,
)
self.stem2b = HGNetV2ConvLayer(
config.stem_channels[1] // 2,
config.stem_channels[1],
kernel_size=2,
stride=1,
activation=config.hidden_act,
use_learnable_affine_block=config.use_learnable_affine_block,
)
self.stem3 = HGNetV2ConvLayer(
config.stem_channels[1] * 2,
config.stem_channels[1],
kernel_size=3,
stride=2,
activation=config.hidden_act,
use_learnable_affine_block=config.use_learnable_affine_block,
)
self.stem4 = HGNetV2ConvLayer(
config.stem_channels[1],
config.stem_channels[2],
kernel_size=1,
stride=1,
activation=config.hidden_act,
use_learnable_affine_block=config.use_learnable_affine_block,
)
self.pool = nn.MaxPool2d(kernel_size=2, stride=1, ceil_mode=True)
self.num_channels = config.num_channels
def forward(self, pixel_values: Tensor) -> Tensor:
num_channels = pixel_values.shape[1]
if num_channels != self.num_channels:
raise ValueError(
"Make sure that the channel dimension of the pixel values match with the one set in the configuration."
)
embedding = self.stem1(pixel_values)
embedding = F.pad(embedding, (0, 1, 0, 1))
emb_stem_2a = self.stem2a(embedding)
emb_stem_2a = F.pad(emb_stem_2a, (0, 1, 0, 1))
emb_stem_2a = self.stem2b(emb_stem_2a)
pooled_emb = self.pool(embedding)
embedding = torch.cat([pooled_emb, emb_stem_2a], dim=1)
embedding = self.stem3(embedding)
embedding = self.stem4(embedding)
return embedding
class HGNetV2BasicLayer(nn.Module):
def __init__(
self,
in_channels: int,
middle_channels: int,
out_channels: int,
layer_num: int,
kernel_size: int = 3,
residual: bool = False,
light_block: bool = False,
drop_path: float = 0.0,
use_learnable_affine_block: bool = False,
):
super().__init__()
self.residual = residual
self.layers = nn.ModuleList()
for i in range(layer_num):
temp_in_channels = in_channels if i == 0 else middle_channels
if light_block:
block = HGNetV2ConvLayerLight(
in_channels=temp_in_channels,
out_channels=middle_channels,
kernel_size=kernel_size,
use_learnable_affine_block=use_learnable_affine_block,
)
else:
block = HGNetV2ConvLayer(
in_channels=temp_in_channels,
out_channels=middle_channels,
kernel_size=kernel_size,
use_learnable_affine_block=use_learnable_affine_block,
stride=1,
)
self.layers.append(block)
# feature aggregation
total_channels = in_channels + layer_num * middle_channels
aggregation_squeeze_conv = HGNetV2ConvLayer(
total_channels,
out_channels // 2,
kernel_size=1,
stride=1,
use_learnable_affine_block=use_learnable_affine_block,
)
aggregation_excitation_conv = HGNetV2ConvLayer(
out_channels // 2,
out_channels,
kernel_size=1,
stride=1,
use_learnable_affine_block=use_learnable_affine_block,
)
self.aggregation = nn.Sequential(
aggregation_squeeze_conv,
aggregation_excitation_conv,
)
self.drop_path = nn.Dropout(drop_path) if drop_path else nn.Identity()
def forward(self, hidden_state: Tensor) -> Tensor:
identity = hidden_state
output = [hidden_state]
for layer in self.layers:
hidden_state = layer(hidden_state)
output.append(hidden_state)
hidden_state = torch.cat(output, dim=1)
hidden_state = self.aggregation(hidden_state)
if self.residual:
hidden_state = self.drop_path(hidden_state) + identity
return hidden_state
class HGNetV2Stage(nn.Module):
def __init__(self, config: HGNetV2Config, stage_index: int, drop_path: float = 0.0):
super().__init__()
in_channels = config.stage_in_channels[stage_index]
mid_channels = config.stage_mid_channels[stage_index]
out_channels = config.stage_out_channels[stage_index]
num_blocks = config.stage_num_blocks[stage_index]
num_layers = config.stage_numb_of_layers[stage_index]
downsample = config.stage_downsample[stage_index]
light_block = config.stage_light_block[stage_index]
kernel_size = config.stage_kernel_size[stage_index]
use_learnable_affine_block = config.use_learnable_affine_block
if downsample:
self.downsample = HGNetV2ConvLayer(
in_channels, in_channels, kernel_size=3, stride=2, groups=in_channels, activation=None
)
else:
self.downsample = nn.Identity()
blocks_list = []
for i in range(num_blocks):
blocks_list.append(
HGNetV2BasicLayer(
in_channels if i == 0 else out_channels,
mid_channels,
out_channels,
num_layers,
residual=False if i == 0 else True,
kernel_size=kernel_size,
light_block=light_block,
drop_path=drop_path,
use_learnable_affine_block=use_learnable_affine_block,
)
)
self.blocks = nn.ModuleList(blocks_list)
def forward(self, hidden_state: Tensor) -> Tensor:
hidden_state = self.downsample(hidden_state)
for block in self.blocks:
hidden_state = block(hidden_state)
return hidden_state
class HGNetV2Encoder(nn.Module):
def __init__(self, config: HGNetV2Config):
super().__init__()
self.stages = nn.ModuleList([])
for stage_index in range(len(config.stage_in_channels)):
resnet_stage = HGNetV2Stage(config, stage_index)
self.stages.append(resnet_stage)
def forward(
self, hidden_state: Tensor, output_hidden_states: bool = False, return_dict: bool = True
) -> BaseModelOutputWithNoAttention:
hidden_states = () if output_hidden_states else None
for stage in self.stages:
if output_hidden_states:
hidden_states = hidden_states + (hidden_state,)
hidden_state = stage(hidden_state)
if output_hidden_states:
hidden_states = hidden_states + (hidden_state,)
if not return_dict:
return tuple(v for v in [hidden_state, hidden_states] if v is not None)
return BaseModelOutputWithNoAttention(
last_hidden_state=hidden_state,
hidden_states=hidden_states,
)
HGNet_V2_INPUTS_DOCSTRING = r"""
Args:
pixel_values (`torch.FloatTensor` of shape `(batch_size, num_channels, height, width)`):
Pixel values. Pixel values can be obtained using [`AutoImageProcessor`]. See
[`RTDetrImageProcessor.__call__`] for details.
output_hidden_states (`bool`, *optional*):
Whether or not to return the hidden states of all layers. See `hidden_states` under returned tensors for
more detail.
return_dict (`bool`, *optional*):
Whether or not to return a [`~utils.ModelOutput`] instead of a plain tuple.
"""
class HGNetV2Backbone(HGNetV2PreTrainedModel, BackboneMixin):
def __init__(self, config: HGNetV2Config):
super().__init__(config)
super()._init_backbone(config)
self.depths = config.depths
self.num_features = [config.embedding_size] + config.hidden_sizes
self.embedder = HGNetV2Embeddings(config)
self.encoder = HGNetV2Encoder(config)
# initialize weights and apply final processing
self.post_init()
@add_start_docstrings_to_model_forward(HGNet_V2_INPUTS_DOCSTRING)
@replace_return_docstrings(output_type=BackboneOutput, config_class=_CONFIG_FOR_DOC)
def forward(
self, pixel_values: Tensor, output_hidden_states: Optional[bool] = None, return_dict: Optional[bool] = None
) -> BackboneOutput:
"""
Returns:
Examples:
```python
>>> from transformers import RTDetrResNetConfig, RTDetrResNetBackbone
>>> import torch
>>> config = RTDetrResNetConfig()
>>> model = RTDetrResNetBackbone(config)
>>> pixel_values = torch.randn(1, 3, 224, 224)
>>> with torch.no_grad():
... outputs = model(pixel_values)
>>> feature_maps = outputs.feature_maps
>>> list(feature_maps[-1].shape)
[1, 2048, 7, 7]
```"""
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
output_hidden_states = (
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
)
embedding_output = self.embedder(pixel_values)
outputs = self.encoder(embedding_output, output_hidden_states=True, return_dict=True)
hidden_states = outputs.hidden_states
feature_maps = ()
for idx, stage in enumerate(self.stage_names):
if stage in self.out_features:
feature_maps += (hidden_states[idx],)
if not return_dict:
output = (feature_maps,)
if output_hidden_states:
output += (outputs.hidden_states,)
return output
return BackboneOutput(
feature_maps=feature_maps,
hidden_states=outputs.hidden_states if output_hidden_states else None,
attentions=None,
)
HGNet_V2_START_DOCSTRING = r"""
This model is a PyTorch [torch.nn.Module](https://pytorch.org/docs/stable/nn.html#torch.nn.Module) subclass. Use it
as a regular PyTorch Module and refer to the PyTorch documentation for all matter related to general usage and
behavior.
Parameters:
config ([`HGNetV2Config`]): Model configuration class with all the parameters of the model.
Initializing with a config file does not load the weights associated with the model, only the
configuration. Check out the [`~PreTrainedModel.from_pretrained`] method to load the model weights.
"""
@add_start_docstrings(
"""
HGNetV2 Model with an image classification head on top (a linear layer on top of the pooled features), e.g. for
ImageNet.
""",
HGNet_V2_START_DOCSTRING,
)
class HGNetV2ForImageClassification(HGNetV2PreTrainedModel):
def __init__(self, config: HGNetV2Config):
super().__init__(config)
self.num_labels = config.num_labels
self.embedder = HGNetV2Embeddings(config)
self.encoder = HGNetV2Encoder(config)
self.avg_pool = nn.AdaptiveAvgPool2d((1, 1))
self.flatten = nn.Flatten()
self.fc = nn.Linear(config.hidden_sizes[-1], config.num_labels) if config.num_labels > 0 else nn.Identity()
# classification head
self.classifier = nn.ModuleList([self.avg_pool, self.flatten])
# initialize weights and apply final processing
self.post_init()
@add_start_docstrings_to_model_forward(HGNet_V2_INPUTS_DOCSTRING)
@replace_return_docstrings(output_type=ImageClassifierOutputWithNoAttention, config_class=_CONFIG_FOR_DOC)
def forward(
self,
pixel_values: Optional[torch.FloatTensor] = None,
labels: Optional[torch.LongTensor] = None,
output_hidden_states: Optional[bool] = None,
return_dict: Optional[bool] = None,
) -> ImageClassifierOutputWithNoAttention:
r"""
labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
Labels for computing the image classification/regression loss. Indices should be in `[0, ...,
config.num_labels - 1]`. If `config.num_labels == 1` a regression loss is computed (Mean-Square loss), If
`config.num_labels > 1` a classification loss is computed (Cross-Entropy).
Returns:
Examples:
```python
>>> import torch
>>> import requests
>>> from transformers import HGNetV2ForImageClassification, AutoImageProcessor
>>> from PIL import Image
>>> url = "http://images.cocodataset.org/val2017/000000039769.jpg"
>>> image = Image.open(requests.get(url, stream=True).raw)
>>> model = HGNetV2ForImageClassification.from_pretrained("ustc-community/hgnet-v2")
>>> processor = AutoImageProcessor.from_pretrained("ustc-community/hgnet-v2")
>>> inputs = processor(images=image, return_tensors="pt")
>>> with torch.no_grad():
... outputs = model(**inputs)
>>> outputs.logits.shape
torch.Size([1, 2])
```"""
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
output_hidden_states = (
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
)
embedding_output = self.embedder(pixel_values)
outputs = self.encoder(embedding_output, output_hidden_states=output_hidden_states, return_dict=return_dict)
last_hidden_state = outputs[0]
for layer in self.classifier:
last_hidden_state = layer(last_hidden_state)
logits = self.fc(last_hidden_state)
loss = None
if labels is not None:
if self.config.problem_type is None:
if self.num_labels == 1:
self.config.problem_type = "regression"
elif self.num_labels > 1 and (labels.dtype == torch.long or labels.dtype == torch.int):
self.config.problem_type = "single_label_classification"
else:
self.config.problem_type = "multi_label_classification"
if self.config.problem_type == "regression":
loss_fct = MSELoss()
if self.num_labels == 1:
loss = loss_fct(logits.squeeze(), labels.squeeze())
else:
loss = loss_fct(logits, labels)
elif self.config.problem_type == "single_label_classification":
loss_fct = CrossEntropyLoss()
loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))
elif self.config.problem_type == "multi_label_classification":
loss_fct = BCEWithLogitsLoss()
loss = loss_fct(logits, labels)
if not return_dict:
output = (logits,) + outputs[2:]
return (loss,) + output if loss is not None else output
return ImageClassifierOutputWithNoAttention(loss=loss, logits=logits, hidden_states=outputs.hidden_states)
__all__ = ["HGNetV2Backbone", "HGNetV2PreTrainedModel", "HGNetV2ForImageClassification"]

View File

@@ -0,0 +1,661 @@
# coding=utf-8
# Copyright 2025 Baidu Inc and The HuggingFace Inc. team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Optional
import torch
import torch.nn.functional as F
from torch import Tensor, nn
from torch.nn import BCEWithLogitsLoss, CrossEntropyLoss, MSELoss
from ...configuration_utils import PretrainedConfig
from ...modeling_outputs import (
BackboneOutput,
BaseModelOutputWithNoAttention,
ImageClassifierOutputWithNoAttention,
)
from ...modeling_utils import PreTrainedModel
from ...utils import add_start_docstrings, add_start_docstrings_to_model_forward, replace_return_docstrings
from ...utils.backbone_utils import BackboneConfigMixin, BackboneMixin, get_aligned_output_features_output_indices
from ..rt_detr.modeling_rt_detr_resnet import RTDetrResNetConvLayer
# TODO: Modular conversion for resnet must be fixed as
# it provides incorrect import for configuration like resnet_resnet
class HGNetV2Config(BackboneConfigMixin, PretrainedConfig):
"""
This is the configuration class to store the configuration of a [`HGNetV2Backbone`]. It is used to instantiate a HGNet-V2
model according to the specified arguments, defining the model architecture. Instantiating a configuration with the
defaults will yield a similar configuration to that of D-FINE-X-COCO B4 "[ustc-community/dfine_x_coco"](https://huggingface.co/ustc-community/dfine_x_coco").
Configuration objects inherit from [`PretrainedConfig`] and can be used to control the model outputs. Read the
documentation from [`PretrainedConfig`] for more information.
Args:
num_channels (`int`, *optional*, defaults to 3):
The number of input channels.
embedding_size (`int`, *optional*, defaults to 64):
Dimensionality (hidden size) for the embedding layer.
depths (`List[int]`, *optional*, defaults to `[3, 4, 6, 3]`):
Depth (number of layers) for each stage.
hidden_sizes (`List[int]`, *optional*, defaults to `[256, 512, 1024, 2048]`):
Dimensionality (hidden size) at each stage.
hidden_act (`str`, *optional*, defaults to `"relu"`):
The non-linear activation function in each block. If string, `"gelu"`, `"relu"`, `"selu"` and `"gelu_new"`
are supported.
out_features (`List[str]`, *optional*):
If used as backbone, list of features to output. Can be any of `"stem"`, `"stage1"`, `"stage2"`, etc.
(depending on how many stages the model has). If unset and `out_indices` is set, will default to the
corresponding stages. If unset and `out_indices` is unset, will default to the last stage. Must be in the
same order as defined in the `stage_names` attribute.
out_indices (`List[int]`, *optional*):
If used as backbone, list of indices of features to output. Can be any of 0, 1, 2, etc. (depending on how
many stages the model has). If unset and `out_features` is set, will default to the corresponding stages.
If unset and `out_features` is unset, will default to the last stage. Must be in the
same order as defined in the `stage_names` attribute.
stem_channels (`List[int]`, *optional*, defaults to `[3, 32, 48]`):
Channel dimensions for the stem layers:
- First number (3) is input image channels
- Second number (32) is intermediate stem channels
- Third number (48) is output stem channels
stage_in_channels (`List[int]`, *optional*, defaults to `[48, 128, 512, 1024]`):
Input channel dimensions for each stage of the backbone.
This defines how many channels the input to each stage will have.
stage_mid_channels (`List[int]`, *optional*, defaults to `[48, 96, 192, 384]`):
Mid-channel dimensions for each stage of the backbone.
This defines the number of channels used in the intermediate layers of each stage.
stage_out_channels (`List[int]`, *optional*, defaults to `[128, 512, 1024, 2048]`):
Output channel dimensions for each stage of the backbone.
This defines how many channels the output of each stage will have.
stage_num_blocks (`List[int]`, *optional*, defaults to `[1, 1, 3, 1]`):
Number of blocks to be used in each stage of the backbone.
This controls the depth of each stage by specifying how many convolutional blocks to stack.
stage_downsample (`List[bool]`, *optional*, defaults to `[False, True, True, True]`):
Indicates whether to downsample the feature maps at each stage.
If `True`, the spatial dimensions of the feature maps will be reduced.
stage_light_block (`List[bool]`, *optional*, defaults to `[False, False, True, True]`):
Indicates whether to use light blocks in each stage.
Light blocks are a variant of convolutional blocks that may have fewer parameters.
stage_kernel_size (`List[int]`, *optional*, defaults to `[3, 3, 5, 5]`):
Kernel sizes for the convolutional layers in each stage.
stage_numb_of_layers (`List[int]`, *optional*, defaults to `[6, 6, 6, 6]`):
Number of layers to be used in each block of the stage.
use_learnable_affine_block (`bool`, *optional*, defaults to `False`):
Whether to use Learnable Affine Blocks (LAB) in the network.
LAB adds learnable scale and bias parameters after certain operations.
initializer_range (`float`, *optional*, defaults to 0.02):
The standard deviation of the truncated_normal_initializer for initializing all weight matrices.
"""
model_type = "hgnet_v2"
def __init__(
self,
num_channels=3,
embedding_size=64,
depths=[3, 4, 6, 3],
hidden_sizes=[256, 512, 1024, 2048],
hidden_act="relu",
out_features=None,
out_indices=None,
stem_channels=[3, 32, 48],
stage_in_channels=[48, 128, 512, 1024],
stage_mid_channels=[48, 96, 192, 384],
stage_out_channels=[128, 512, 1024, 2048],
stage_num_blocks=[1, 1, 3, 1],
stage_downsample=[False, True, True, True],
stage_light_block=[False, False, True, True],
stage_kernel_size=[3, 3, 5, 5],
stage_numb_of_layers=[6, 6, 6, 6],
use_learnable_affine_block=False,
initializer_range=0.02,
**kwargs,
):
super().__init__(**kwargs)
self.num_channels = num_channels
self.embedding_size = embedding_size
self.depths = depths
self.hidden_sizes = hidden_sizes
self.hidden_act = hidden_act
self.stage_names = ["stem"] + [f"stage{idx}" for idx in range(1, len(depths) + 1)]
self._out_features, self._out_indices = get_aligned_output_features_output_indices(
out_features=out_features, out_indices=out_indices, stage_names=self.stage_names
)
self.stem_channels = stem_channels
self.stage_in_channels = stage_in_channels
self.stage_mid_channels = stage_mid_channels
self.stage_out_channels = stage_out_channels
self.stage_num_blocks = stage_num_blocks
self.stage_downsample = stage_downsample
self.stage_light_block = stage_light_block
self.stage_kernel_size = stage_kernel_size
self.stage_numb_of_layers = stage_numb_of_layers
self.use_learnable_affine_block = use_learnable_affine_block
self.initializer_range = initializer_range
if not (
len(stage_in_channels)
== len(stage_mid_channels)
== len(stage_out_channels)
== len(stage_num_blocks)
== len(stage_downsample)
== len(stage_light_block)
== len(stage_kernel_size)
== len(stage_numb_of_layers)
):
raise ValueError("All stage configuration lists must have the same length.")
# General docstring
_CONFIG_FOR_DOC = "HGNetV2Config"
class HGNetV2PreTrainedModel(PreTrainedModel):
"""
An abstract class to handle weights initialization and a simple interface for downloading and loading pretrained
models.
"""
config_class = HGNetV2Config
base_model_prefix = "hgnetv2"
main_input_name = "pixel_values"
_no_split_modules = ["HGNetV2BasicLayer"]
def _init_weights(self, module):
if isinstance(module, (nn.Linear, nn.Conv2d)):
module.weight.data.normal_(mean=0.0, std=self.config.initializer_range)
if module.bias is not None:
module.bias.data.zero_()
elif isinstance(module, nn.BatchNorm2d):
module.weight.data.fill_(1.0)
if module.bias is not None:
module.bias.data.zero_()
class HGNetV2LearnableAffineBlock(nn.Module):
def __init__(self, scale_value: float = 1.0, bias_value: float = 0.0):
super().__init__()
self.scale = nn.Parameter(torch.tensor([scale_value]), requires_grad=True)
self.bias = nn.Parameter(torch.tensor([bias_value]), requires_grad=True)
def forward(self, hidden_state: Tensor) -> Tensor:
hidden_state = self.scale * hidden_state + self.bias
return hidden_state
class HGNetV2ConvLayer(RTDetrResNetConvLayer):
def __init__(
self,
in_channels: int,
out_channels: int,
kernel_size: int,
stride: int = 1,
groups: int = 1,
activation: str = "relu",
use_learnable_affine_block: bool = False,
):
super().__init__(in_channels, out_channels, kernel_size, stride, activation)
self.convolution = nn.Conv2d(
in_channels,
out_channels,
kernel_size=kernel_size,
stride=stride,
groups=groups,
padding=(kernel_size - 1) // 2,
bias=False,
)
if activation and use_learnable_affine_block:
self.lab = HGNetV2LearnableAffineBlock()
else:
self.lab = nn.Identity()
def forward(self, input: Tensor) -> Tensor:
hidden_state = self.convolution(input)
hidden_state = self.normalization(hidden_state)
hidden_state = self.activation(hidden_state)
hidden_state = self.lab(hidden_state)
return hidden_state
class HGNetV2ConvLayerLight(nn.Module):
def __init__(
self, in_channels: int, out_channels: int, kernel_size: int, use_learnable_affine_block: bool = False
):
super().__init__()
self.conv1 = HGNetV2ConvLayer(
in_channels,
out_channels,
kernel_size=1,
activation=None,
use_learnable_affine_block=use_learnable_affine_block,
)
self.conv2 = HGNetV2ConvLayer(
out_channels,
out_channels,
kernel_size=kernel_size,
groups=out_channels,
use_learnable_affine_block=use_learnable_affine_block,
)
def forward(self, hidden_state: Tensor) -> Tensor:
hidden_state = self.conv1(hidden_state)
hidden_state = self.conv2(hidden_state)
return hidden_state
class HGNetV2Embeddings(nn.Module):
def __init__(self, config: HGNetV2Config):
super().__init__()
self.stem1 = HGNetV2ConvLayer(
config.stem_channels[0],
config.stem_channels[1],
kernel_size=3,
stride=2,
activation=config.hidden_act,
use_learnable_affine_block=config.use_learnable_affine_block,
)
self.stem2a = HGNetV2ConvLayer(
config.stem_channels[1],
config.stem_channels[1] // 2,
kernel_size=2,
stride=1,
activation=config.hidden_act,
use_learnable_affine_block=config.use_learnable_affine_block,
)
self.stem2b = HGNetV2ConvLayer(
config.stem_channels[1] // 2,
config.stem_channels[1],
kernel_size=2,
stride=1,
activation=config.hidden_act,
use_learnable_affine_block=config.use_learnable_affine_block,
)
self.stem3 = HGNetV2ConvLayer(
config.stem_channels[1] * 2,
config.stem_channels[1],
kernel_size=3,
stride=2,
activation=config.hidden_act,
use_learnable_affine_block=config.use_learnable_affine_block,
)
self.stem4 = HGNetV2ConvLayer(
config.stem_channels[1],
config.stem_channels[2],
kernel_size=1,
stride=1,
activation=config.hidden_act,
use_learnable_affine_block=config.use_learnable_affine_block,
)
self.pool = nn.MaxPool2d(kernel_size=2, stride=1, ceil_mode=True)
self.num_channels = config.num_channels
def forward(self, pixel_values: Tensor) -> Tensor:
num_channels = pixel_values.shape[1]
if num_channels != self.num_channels:
raise ValueError(
"Make sure that the channel dimension of the pixel values match with the one set in the configuration."
)
embedding = self.stem1(pixel_values)
embedding = F.pad(embedding, (0, 1, 0, 1))
emb_stem_2a = self.stem2a(embedding)
emb_stem_2a = F.pad(emb_stem_2a, (0, 1, 0, 1))
emb_stem_2a = self.stem2b(emb_stem_2a)
pooled_emb = self.pool(embedding)
embedding = torch.cat([pooled_emb, emb_stem_2a], dim=1)
embedding = self.stem3(embedding)
embedding = self.stem4(embedding)
return embedding
class HGNetV2BasicLayer(nn.Module):
def __init__(
self,
in_channels: int,
middle_channels: int,
out_channels: int,
layer_num: int,
kernel_size: int = 3,
residual: bool = False,
light_block: bool = False,
drop_path: float = 0.0,
use_learnable_affine_block: bool = False,
):
super().__init__()
self.residual = residual
self.layers = nn.ModuleList()
for i in range(layer_num):
temp_in_channels = in_channels if i == 0 else middle_channels
if light_block:
block = HGNetV2ConvLayerLight(
in_channels=temp_in_channels,
out_channels=middle_channels,
kernel_size=kernel_size,
use_learnable_affine_block=use_learnable_affine_block,
)
else:
block = HGNetV2ConvLayer(
in_channels=temp_in_channels,
out_channels=middle_channels,
kernel_size=kernel_size,
use_learnable_affine_block=use_learnable_affine_block,
stride=1,
)
self.layers.append(block)
# feature aggregation
total_channels = in_channels + layer_num * middle_channels
aggregation_squeeze_conv = HGNetV2ConvLayer(
total_channels,
out_channels // 2,
kernel_size=1,
stride=1,
use_learnable_affine_block=use_learnable_affine_block,
)
aggregation_excitation_conv = HGNetV2ConvLayer(
out_channels // 2,
out_channels,
kernel_size=1,
stride=1,
use_learnable_affine_block=use_learnable_affine_block,
)
self.aggregation = nn.Sequential(
aggregation_squeeze_conv,
aggregation_excitation_conv,
)
self.drop_path = nn.Dropout(drop_path) if drop_path else nn.Identity()
def forward(self, hidden_state: Tensor) -> Tensor:
identity = hidden_state
output = [hidden_state]
for layer in self.layers:
hidden_state = layer(hidden_state)
output.append(hidden_state)
hidden_state = torch.cat(output, dim=1)
hidden_state = self.aggregation(hidden_state)
if self.residual:
hidden_state = self.drop_path(hidden_state) + identity
return hidden_state
class HGNetV2Stage(nn.Module):
def __init__(self, config: HGNetV2Config, stage_index: int, drop_path: float = 0.0):
super().__init__()
in_channels = config.stage_in_channels[stage_index]
mid_channels = config.stage_mid_channels[stage_index]
out_channels = config.stage_out_channels[stage_index]
num_blocks = config.stage_num_blocks[stage_index]
num_layers = config.stage_numb_of_layers[stage_index]
downsample = config.stage_downsample[stage_index]
light_block = config.stage_light_block[stage_index]
kernel_size = config.stage_kernel_size[stage_index]
use_learnable_affine_block = config.use_learnable_affine_block
if downsample:
self.downsample = HGNetV2ConvLayer(
in_channels, in_channels, kernel_size=3, stride=2, groups=in_channels, activation=None
)
else:
self.downsample = nn.Identity()
blocks_list = []
for i in range(num_blocks):
blocks_list.append(
HGNetV2BasicLayer(
in_channels if i == 0 else out_channels,
mid_channels,
out_channels,
num_layers,
residual=False if i == 0 else True,
kernel_size=kernel_size,
light_block=light_block,
drop_path=drop_path,
use_learnable_affine_block=use_learnable_affine_block,
)
)
self.blocks = nn.ModuleList(blocks_list)
def forward(self, hidden_state: Tensor) -> Tensor:
hidden_state = self.downsample(hidden_state)
for block in self.blocks:
hidden_state = block(hidden_state)
return hidden_state
class HGNetV2Encoder(nn.Module):
def __init__(self, config: HGNetV2Config):
super().__init__()
self.stages = nn.ModuleList([])
for stage_index in range(len(config.stage_in_channels)):
resnet_stage = HGNetV2Stage(config, stage_index)
self.stages.append(resnet_stage)
def forward(
self, hidden_state: Tensor, output_hidden_states: bool = False, return_dict: bool = True
) -> BaseModelOutputWithNoAttention:
hidden_states = () if output_hidden_states else None
for stage in self.stages:
if output_hidden_states:
hidden_states = hidden_states + (hidden_state,)
hidden_state = stage(hidden_state)
if output_hidden_states:
hidden_states = hidden_states + (hidden_state,)
if not return_dict:
return tuple(v for v in [hidden_state, hidden_states] if v is not None)
return BaseModelOutputWithNoAttention(
last_hidden_state=hidden_state,
hidden_states=hidden_states,
)
HGNet_V2_START_DOCSTRING = r"""
This model is a PyTorch [torch.nn.Module](https://pytorch.org/docs/stable/nn.html#torch.nn.Module) subclass. Use it
as a regular PyTorch Module and refer to the PyTorch documentation for all matter related to general usage and
behavior.
Parameters:
config ([`HGNetV2Config`]): Model configuration class with all the parameters of the model.
Initializing with a config file does not load the weights associated with the model, only the
configuration. Check out the [`~PreTrainedModel.from_pretrained`] method to load the model weights.
"""
HGNet_V2_INPUTS_DOCSTRING = r"""
Args:
pixel_values (`torch.FloatTensor` of shape `(batch_size, num_channels, height, width)`):
Pixel values. Pixel values can be obtained using [`AutoImageProcessor`]. See
[`RTDetrImageProcessor.__call__`] for details.
output_hidden_states (`bool`, *optional*):
Whether or not to return the hidden states of all layers. See `hidden_states` under returned tensors for
more detail.
return_dict (`bool`, *optional*):
Whether or not to return a [`~utils.ModelOutput`] instead of a plain tuple.
"""
class HGNetV2Backbone(HGNetV2PreTrainedModel, BackboneMixin):
def __init__(self, config: HGNetV2Config):
super().__init__(config)
super()._init_backbone(config)
self.depths = config.depths
self.num_features = [config.embedding_size] + config.hidden_sizes
self.embedder = HGNetV2Embeddings(config)
self.encoder = HGNetV2Encoder(config)
# initialize weights and apply final processing
self.post_init()
@add_start_docstrings_to_model_forward(HGNet_V2_INPUTS_DOCSTRING)
@replace_return_docstrings(output_type=BackboneOutput, config_class=_CONFIG_FOR_DOC)
def forward(
self, pixel_values: Tensor, output_hidden_states: Optional[bool] = None, return_dict: Optional[bool] = None
) -> BackboneOutput:
"""
Returns:
Examples:
```python
>>> from transformers import RTDetrResNetConfig, RTDetrResNetBackbone
>>> import torch
>>> config = RTDetrResNetConfig()
>>> model = RTDetrResNetBackbone(config)
>>> pixel_values = torch.randn(1, 3, 224, 224)
>>> with torch.no_grad():
... outputs = model(pixel_values)
>>> feature_maps = outputs.feature_maps
>>> list(feature_maps[-1].shape)
[1, 2048, 7, 7]
```"""
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
output_hidden_states = (
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
)
embedding_output = self.embedder(pixel_values)
outputs = self.encoder(embedding_output, output_hidden_states=True, return_dict=True)
hidden_states = outputs.hidden_states
feature_maps = ()
for idx, stage in enumerate(self.stage_names):
if stage in self.out_features:
feature_maps += (hidden_states[idx],)
if not return_dict:
output = (feature_maps,)
if output_hidden_states:
output += (outputs.hidden_states,)
return output
return BackboneOutput(
feature_maps=feature_maps,
hidden_states=outputs.hidden_states if output_hidden_states else None,
attentions=None,
)
@add_start_docstrings(
"""
HGNetV2 Model with an image classification head on top (a linear layer on top of the pooled features), e.g. for
ImageNet.
""",
HGNet_V2_START_DOCSTRING,
)
class HGNetV2ForImageClassification(HGNetV2PreTrainedModel):
def __init__(self, config: HGNetV2Config):
super().__init__(config)
self.num_labels = config.num_labels
self.embedder = HGNetV2Embeddings(config)
self.encoder = HGNetV2Encoder(config)
self.avg_pool = nn.AdaptiveAvgPool2d((1, 1))
self.flatten = nn.Flatten()
self.fc = nn.Linear(config.hidden_sizes[-1], config.num_labels) if config.num_labels > 0 else nn.Identity()
# classification head
self.classifier = nn.ModuleList([self.avg_pool, self.flatten])
# initialize weights and apply final processing
self.post_init()
@add_start_docstrings_to_model_forward(HGNet_V2_INPUTS_DOCSTRING)
@replace_return_docstrings(output_type=ImageClassifierOutputWithNoAttention, config_class=_CONFIG_FOR_DOC)
def forward(
self,
pixel_values: Optional[torch.FloatTensor] = None,
labels: Optional[torch.LongTensor] = None,
output_hidden_states: Optional[bool] = None,
return_dict: Optional[bool] = None,
) -> ImageClassifierOutputWithNoAttention:
r"""
labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
Labels for computing the image classification/regression loss. Indices should be in `[0, ...,
config.num_labels - 1]`. If `config.num_labels == 1` a regression loss is computed (Mean-Square loss), If
`config.num_labels > 1` a classification loss is computed (Cross-Entropy).
Returns:
Examples:
```python
>>> import torch
>>> import requests
>>> from transformers import HGNetV2ForImageClassification, AutoImageProcessor
>>> from PIL import Image
>>> url = "http://images.cocodataset.org/val2017/000000039769.jpg"
>>> image = Image.open(requests.get(url, stream=True).raw)
>>> model = HGNetV2ForImageClassification.from_pretrained("ustc-community/hgnet-v2")
>>> processor = AutoImageProcessor.from_pretrained("ustc-community/hgnet-v2")
>>> inputs = processor(images=image, return_tensors="pt")
>>> with torch.no_grad():
... outputs = model(**inputs)
>>> outputs.logits.shape
torch.Size([1, 2])
```"""
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
output_hidden_states = (
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
)
embedding_output = self.embedder(pixel_values)
outputs = self.encoder(embedding_output, output_hidden_states=output_hidden_states, return_dict=return_dict)
last_hidden_state = outputs[0]
for layer in self.classifier:
last_hidden_state = layer(last_hidden_state)
logits = self.fc(last_hidden_state)
loss = None
if labels is not None:
if self.config.problem_type is None:
if self.num_labels == 1:
self.config.problem_type = "regression"
elif self.num_labels > 1 and (labels.dtype == torch.long or labels.dtype == torch.int):
self.config.problem_type = "single_label_classification"
else:
self.config.problem_type = "multi_label_classification"
if self.config.problem_type == "regression":
loss_fct = MSELoss()
if self.num_labels == 1:
loss = loss_fct(logits.squeeze(), labels.squeeze())
else:
loss = loss_fct(logits, labels)
elif self.config.problem_type == "single_label_classification":
loss_fct = CrossEntropyLoss()
loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))
elif self.config.problem_type == "multi_label_classification":
loss_fct = BCEWithLogitsLoss()
loss = loss_fct(logits, labels)
if not return_dict:
output = (logits,) + outputs[2:]
return (loss,) + output if loss is not None else output
return ImageClassifierOutputWithNoAttention(loss=loss, logits=logits, hidden_states=outputs.hidden_states)
__all__ = ["HGNetV2Config", "HGNetV2Backbone", "HGNetV2PreTrainedModel", "HGNetV2ForImageClassification"]

View File

@@ -123,6 +123,10 @@ class RTDetrDecoderOutput(ModelOutput):
Stacked intermediate logits (logits of each layer of the decoder). Stacked intermediate logits (logits of each layer of the decoder).
intermediate_reference_points (`torch.FloatTensor` of shape `(batch_size, config.decoder_layers, sequence_length, hidden_size)`): intermediate_reference_points (`torch.FloatTensor` of shape `(batch_size, config.decoder_layers, sequence_length, hidden_size)`):
Stacked intermediate reference points (reference points of each layer of the decoder). Stacked intermediate reference points (reference points of each layer of the decoder).
intermediate_predicted_corners (`torch.FloatTensor` of shape `(batch_size, config.decoder_layers, num_queries, 4)`):
Stacked intermediate predicted corners (predicted corners of each layer of the decoder).
initial_reference_points (`torch.FloatTensor` of shape `(batch_size, config.decoder_layers, num_queries, 4)`):
Stacked initial reference points (initial reference points of each layer of the decoder).
hidden_states (`tuple(torch.FloatTensor)`, *optional*, returned when `output_hidden_states=True` is passed or when `config.output_hidden_states=True`): hidden_states (`tuple(torch.FloatTensor)`, *optional*, returned when `output_hidden_states=True` is passed or when `config.output_hidden_states=True`):
Tuple of `torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer) of Tuple of `torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer) of
shape `(batch_size, sequence_length, hidden_size)`. Hidden-states of the model at the output of each layer shape `(batch_size, sequence_length, hidden_size)`. Hidden-states of the model at the output of each layer
@@ -141,6 +145,8 @@ class RTDetrDecoderOutput(ModelOutput):
intermediate_hidden_states: Optional[torch.FloatTensor] = None intermediate_hidden_states: Optional[torch.FloatTensor] = None
intermediate_logits: Optional[torch.FloatTensor] = None intermediate_logits: Optional[torch.FloatTensor] = None
intermediate_reference_points: Optional[torch.FloatTensor] = None intermediate_reference_points: Optional[torch.FloatTensor] = None
intermediate_predicted_corners: Optional[torch.FloatTensor] = None
initial_reference_points: Optional[torch.FloatTensor] = None
hidden_states: Optional[Tuple[torch.FloatTensor]] = None hidden_states: Optional[Tuple[torch.FloatTensor]] = None
attentions: Optional[Tuple[torch.FloatTensor]] = None attentions: Optional[Tuple[torch.FloatTensor]] = None
cross_attentions: Optional[Tuple[torch.FloatTensor]] = None cross_attentions: Optional[Tuple[torch.FloatTensor]] = None
@@ -204,6 +210,8 @@ class RTDetrModelOutput(ModelOutput):
intermediate_hidden_states: Optional[torch.FloatTensor] = None intermediate_hidden_states: Optional[torch.FloatTensor] = None
intermediate_logits: Optional[torch.FloatTensor] = None intermediate_logits: Optional[torch.FloatTensor] = None
intermediate_reference_points: Optional[torch.FloatTensor] = None intermediate_reference_points: Optional[torch.FloatTensor] = None
intermediate_predicted_corners: Optional[torch.FloatTensor] = None
initial_reference_points: Optional[torch.FloatTensor] = None
decoder_hidden_states: Optional[Tuple[torch.FloatTensor]] = None decoder_hidden_states: Optional[Tuple[torch.FloatTensor]] = None
decoder_attentions: Optional[Tuple[torch.FloatTensor]] = None decoder_attentions: Optional[Tuple[torch.FloatTensor]] = None
cross_attentions: Optional[Tuple[torch.FloatTensor]] = None cross_attentions: Optional[Tuple[torch.FloatTensor]] = None
@@ -249,6 +257,10 @@ class RTDetrObjectDetectionOutput(ModelOutput):
Stacked intermediate logits (logits of each layer of the decoder). Stacked intermediate logits (logits of each layer of the decoder).
intermediate_reference_points (`torch.FloatTensor` of shape `(batch_size, config.decoder_layers, num_queries, 4)`): intermediate_reference_points (`torch.FloatTensor` of shape `(batch_size, config.decoder_layers, num_queries, 4)`):
Stacked intermediate reference points (reference points of each layer of the decoder). Stacked intermediate reference points (reference points of each layer of the decoder).
intermediate_predicted_corners (`torch.FloatTensor` of shape `(batch_size, config.decoder_layers, num_queries, 4)`):
Stacked intermediate predicted corners (predicted corners of each layer of the decoder).
initial_reference_points (`torch.FloatTensor` of shape `(batch_size, config.decoder_layers, num_queries, 4)`):
Stacked initial reference points (initial reference points of each layer of the decoder).
decoder_hidden_states (`tuple(torch.FloatTensor)`, *optional*, returned when `output_hidden_states=True` is passed or when `config.output_hidden_states=True`): decoder_hidden_states (`tuple(torch.FloatTensor)`, *optional*, returned when `output_hidden_states=True` is passed or when `config.output_hidden_states=True`):
Tuple of `torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer) of Tuple of `torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer) of
shape `(batch_size, num_queries, hidden_size)`. Hidden-states of the decoder at the output of each layer shape `(batch_size, num_queries, hidden_size)`. Hidden-states of the decoder at the output of each layer
@@ -296,6 +308,8 @@ class RTDetrObjectDetectionOutput(ModelOutput):
intermediate_hidden_states: Optional[torch.FloatTensor] = None intermediate_hidden_states: Optional[torch.FloatTensor] = None
intermediate_logits: Optional[torch.FloatTensor] = None intermediate_logits: Optional[torch.FloatTensor] = None
intermediate_reference_points: Optional[torch.FloatTensor] = None intermediate_reference_points: Optional[torch.FloatTensor] = None
intermediate_predicted_corners: Optional[torch.FloatTensor] = None
initial_reference_points: Optional[torch.FloatTensor] = None
decoder_hidden_states: Optional[Tuple[torch.FloatTensor]] = None decoder_hidden_states: Optional[Tuple[torch.FloatTensor]] = None
decoder_attentions: Optional[Tuple[torch.FloatTensor]] = None decoder_attentions: Optional[Tuple[torch.FloatTensor]] = None
cross_attentions: Optional[Tuple[torch.FloatTensor]] = None cross_attentions: Optional[Tuple[torch.FloatTensor]] = None
@@ -1468,8 +1482,8 @@ class RTDetrDecoder(RTDetrPreTrainedModel):
# hack implementation for iterative bounding box refinement # hack implementation for iterative bounding box refinement
if self.bbox_embed is not None: if self.bbox_embed is not None:
tmp = self.bbox_embed[idx](hidden_states) predicted_corners = self.bbox_embed[idx](hidden_states)
new_reference_points = F.sigmoid(tmp + inverse_sigmoid(reference_points)) new_reference_points = F.sigmoid(predicted_corners + inverse_sigmoid(reference_points))
reference_points = new_reference_points.detach() reference_points = new_reference_points.detach()
intermediate += (hidden_states,) intermediate += (hidden_states,)
@@ -1865,6 +1879,8 @@ class RTDetrModel(RTDetrPreTrainedModel):
intermediate_hidden_states=decoder_outputs.intermediate_hidden_states, intermediate_hidden_states=decoder_outputs.intermediate_hidden_states,
intermediate_logits=decoder_outputs.intermediate_logits, intermediate_logits=decoder_outputs.intermediate_logits,
intermediate_reference_points=decoder_outputs.intermediate_reference_points, intermediate_reference_points=decoder_outputs.intermediate_reference_points,
intermediate_predicted_corners=decoder_outputs.intermediate_predicted_corners,
initial_reference_points=decoder_outputs.initial_reference_points,
decoder_hidden_states=decoder_outputs.hidden_states, decoder_hidden_states=decoder_outputs.hidden_states,
decoder_attentions=decoder_outputs.attentions, decoder_attentions=decoder_outputs.attentions,
cross_attentions=decoder_outputs.cross_attentions, cross_attentions=decoder_outputs.cross_attentions,
@@ -2020,6 +2036,8 @@ class RTDetrForObjectDetection(RTDetrPreTrainedModel):
outputs_class = outputs.intermediate_logits if return_dict else outputs[2] outputs_class = outputs.intermediate_logits if return_dict else outputs[2]
outputs_coord = outputs.intermediate_reference_points if return_dict else outputs[3] outputs_coord = outputs.intermediate_reference_points if return_dict else outputs[3]
predicted_corners = outputs.intermediate_predicted_corners if return_dict else outputs[4]
initial_reference_points = outputs.initial_reference_points if return_dict else outputs[5]
logits = outputs_class[:, -1] logits = outputs_class[:, -1]
pred_boxes = outputs_coord[:, -1] pred_boxes = outputs_coord[:, -1]
@@ -2039,6 +2057,8 @@ class RTDetrForObjectDetection(RTDetrPreTrainedModel):
enc_topk_logits=enc_topk_logits, enc_topk_logits=enc_topk_logits,
enc_topk_bboxes=enc_topk_bboxes, enc_topk_bboxes=enc_topk_bboxes,
denoising_meta_values=denoising_meta_values, denoising_meta_values=denoising_meta_values,
predicted_corners=predicted_corners,
initial_reference_points=initial_reference_points,
**loss_kwargs, **loss_kwargs,
) )
@@ -2059,6 +2079,8 @@ class RTDetrForObjectDetection(RTDetrPreTrainedModel):
intermediate_hidden_states=outputs.intermediate_hidden_states, intermediate_hidden_states=outputs.intermediate_hidden_states,
intermediate_logits=outputs.intermediate_logits, intermediate_logits=outputs.intermediate_logits,
intermediate_reference_points=outputs.intermediate_reference_points, intermediate_reference_points=outputs.intermediate_reference_points,
intermediate_predicted_corners=outputs.intermediate_predicted_corners,
initial_reference_points=outputs.initial_reference_points,
decoder_hidden_states=outputs.decoder_hidden_states, decoder_hidden_states=outputs.decoder_hidden_states,
decoder_attentions=outputs.decoder_attentions, decoder_attentions=outputs.decoder_attentions,
cross_attentions=outputs.cross_attentions, cross_attentions=outputs.cross_attentions,

View File

@@ -472,6 +472,10 @@ class RTDetrV2DecoderOutput(ModelOutput):
Stacked intermediate logits (logits of each layer of the decoder). Stacked intermediate logits (logits of each layer of the decoder).
intermediate_reference_points (`torch.FloatTensor` of shape `(batch_size, config.decoder_layers, sequence_length, hidden_size)`): intermediate_reference_points (`torch.FloatTensor` of shape `(batch_size, config.decoder_layers, sequence_length, hidden_size)`):
Stacked intermediate reference points (reference points of each layer of the decoder). Stacked intermediate reference points (reference points of each layer of the decoder).
intermediate_predicted_corners (`torch.FloatTensor` of shape `(batch_size, config.decoder_layers, num_queries, 4)`):
Stacked intermediate predicted corners (predicted corners of each layer of the decoder).
initial_reference_points (`torch.FloatTensor` of shape `(batch_size, config.decoder_layers, num_queries, 4)`):
Stacked initial reference points (initial reference points of each layer of the decoder).
hidden_states (`tuple(torch.FloatTensor)`, *optional*, returned when `output_hidden_states=True` is passed or when `config.output_hidden_states=True`): hidden_states (`tuple(torch.FloatTensor)`, *optional*, returned when `output_hidden_states=True` is passed or when `config.output_hidden_states=True`):
Tuple of `torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer) of Tuple of `torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer) of
shape `(batch_size, sequence_length, hidden_size)`. Hidden-states of the model at the output of each layer shape `(batch_size, sequence_length, hidden_size)`. Hidden-states of the model at the output of each layer
@@ -490,6 +494,8 @@ class RTDetrV2DecoderOutput(ModelOutput):
intermediate_hidden_states: Optional[torch.FloatTensor] = None intermediate_hidden_states: Optional[torch.FloatTensor] = None
intermediate_logits: Optional[torch.FloatTensor] = None intermediate_logits: Optional[torch.FloatTensor] = None
intermediate_reference_points: Optional[torch.FloatTensor] = None intermediate_reference_points: Optional[torch.FloatTensor] = None
intermediate_predicted_corners: Optional[torch.FloatTensor] = None
initial_reference_points: Optional[torch.FloatTensor] = None
hidden_states: Optional[Tuple[torch.FloatTensor]] = None hidden_states: Optional[Tuple[torch.FloatTensor]] = None
attentions: Optional[Tuple[torch.FloatTensor]] = None attentions: Optional[Tuple[torch.FloatTensor]] = None
cross_attentions: Optional[Tuple[torch.FloatTensor]] = None cross_attentions: Optional[Tuple[torch.FloatTensor]] = None
@@ -553,6 +559,8 @@ class RTDetrV2ModelOutput(ModelOutput):
intermediate_hidden_states: Optional[torch.FloatTensor] = None intermediate_hidden_states: Optional[torch.FloatTensor] = None
intermediate_logits: Optional[torch.FloatTensor] = None intermediate_logits: Optional[torch.FloatTensor] = None
intermediate_reference_points: Optional[torch.FloatTensor] = None intermediate_reference_points: Optional[torch.FloatTensor] = None
intermediate_predicted_corners: Optional[torch.FloatTensor] = None
initial_reference_points: Optional[torch.FloatTensor] = None
decoder_hidden_states: Optional[Tuple[torch.FloatTensor]] = None decoder_hidden_states: Optional[Tuple[torch.FloatTensor]] = None
decoder_attentions: Optional[Tuple[torch.FloatTensor]] = None decoder_attentions: Optional[Tuple[torch.FloatTensor]] = None
cross_attentions: Optional[Tuple[torch.FloatTensor]] = None cross_attentions: Optional[Tuple[torch.FloatTensor]] = None
@@ -598,6 +606,10 @@ class RTDetrV2ObjectDetectionOutput(ModelOutput):
Stacked intermediate logits (logits of each layer of the decoder). Stacked intermediate logits (logits of each layer of the decoder).
intermediate_reference_points (`torch.FloatTensor` of shape `(batch_size, config.decoder_layers, num_queries, 4)`): intermediate_reference_points (`torch.FloatTensor` of shape `(batch_size, config.decoder_layers, num_queries, 4)`):
Stacked intermediate reference points (reference points of each layer of the decoder). Stacked intermediate reference points (reference points of each layer of the decoder).
intermediate_predicted_corners (`torch.FloatTensor` of shape `(batch_size, config.decoder_layers, num_queries, 4)`):
Stacked intermediate predicted corners (predicted corners of each layer of the decoder).
initial_reference_points (`torch.FloatTensor` of shape `(batch_size, config.decoder_layers, num_queries, 4)`):
Stacked initial reference points (initial reference points of each layer of the decoder).
decoder_hidden_states (`tuple(torch.FloatTensor)`, *optional*, returned when `output_hidden_states=True` is passed or when `config.output_hidden_states=True`): decoder_hidden_states (`tuple(torch.FloatTensor)`, *optional*, returned when `output_hidden_states=True` is passed or when `config.output_hidden_states=True`):
Tuple of `torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer) of Tuple of `torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer) of
shape `(batch_size, num_queries, hidden_size)`. Hidden-states of the decoder at the output of each layer shape `(batch_size, num_queries, hidden_size)`. Hidden-states of the decoder at the output of each layer
@@ -645,6 +657,8 @@ class RTDetrV2ObjectDetectionOutput(ModelOutput):
intermediate_hidden_states: Optional[torch.FloatTensor] = None intermediate_hidden_states: Optional[torch.FloatTensor] = None
intermediate_logits: Optional[torch.FloatTensor] = None intermediate_logits: Optional[torch.FloatTensor] = None
intermediate_reference_points: Optional[torch.FloatTensor] = None intermediate_reference_points: Optional[torch.FloatTensor] = None
intermediate_predicted_corners: Optional[torch.FloatTensor] = None
initial_reference_points: Optional[torch.FloatTensor] = None
decoder_hidden_states: Optional[Tuple[torch.FloatTensor]] = None decoder_hidden_states: Optional[Tuple[torch.FloatTensor]] = None
decoder_attentions: Optional[Tuple[torch.FloatTensor]] = None decoder_attentions: Optional[Tuple[torch.FloatTensor]] = None
cross_attentions: Optional[Tuple[torch.FloatTensor]] = None cross_attentions: Optional[Tuple[torch.FloatTensor]] = None
@@ -1476,8 +1490,8 @@ class RTDetrV2Decoder(RTDetrV2PreTrainedModel):
# hack implementation for iterative bounding box refinement # hack implementation for iterative bounding box refinement
if self.bbox_embed is not None: if self.bbox_embed is not None:
tmp = self.bbox_embed[idx](hidden_states) predicted_corners = self.bbox_embed[idx](hidden_states)
new_reference_points = F.sigmoid(tmp + inverse_sigmoid(reference_points)) new_reference_points = F.sigmoid(predicted_corners + inverse_sigmoid(reference_points))
reference_points = new_reference_points.detach() reference_points = new_reference_points.detach()
intermediate += (hidden_states,) intermediate += (hidden_states,)
@@ -1849,6 +1863,8 @@ class RTDetrV2Model(RTDetrV2PreTrainedModel):
intermediate_hidden_states=decoder_outputs.intermediate_hidden_states, intermediate_hidden_states=decoder_outputs.intermediate_hidden_states,
intermediate_logits=decoder_outputs.intermediate_logits, intermediate_logits=decoder_outputs.intermediate_logits,
intermediate_reference_points=decoder_outputs.intermediate_reference_points, intermediate_reference_points=decoder_outputs.intermediate_reference_points,
intermediate_predicted_corners=decoder_outputs.intermediate_predicted_corners,
initial_reference_points=decoder_outputs.initial_reference_points,
decoder_hidden_states=decoder_outputs.hidden_states, decoder_hidden_states=decoder_outputs.hidden_states,
decoder_attentions=decoder_outputs.attentions, decoder_attentions=decoder_outputs.attentions,
cross_attentions=decoder_outputs.cross_attentions, cross_attentions=decoder_outputs.cross_attentions,
@@ -2019,6 +2035,8 @@ class RTDetrV2ForObjectDetection(RTDetrV2PreTrainedModel):
outputs_class = outputs.intermediate_logits if return_dict else outputs[2] outputs_class = outputs.intermediate_logits if return_dict else outputs[2]
outputs_coord = outputs.intermediate_reference_points if return_dict else outputs[3] outputs_coord = outputs.intermediate_reference_points if return_dict else outputs[3]
predicted_corners = outputs.intermediate_predicted_corners if return_dict else outputs[4]
initial_reference_points = outputs.initial_reference_points if return_dict else outputs[5]
logits = outputs_class[:, -1] logits = outputs_class[:, -1]
pred_boxes = outputs_coord[:, -1] pred_boxes = outputs_coord[:, -1]
@@ -2038,6 +2056,8 @@ class RTDetrV2ForObjectDetection(RTDetrV2PreTrainedModel):
enc_topk_logits=enc_topk_logits, enc_topk_logits=enc_topk_logits,
enc_topk_bboxes=enc_topk_bboxes, enc_topk_bboxes=enc_topk_bboxes,
denoising_meta_values=denoising_meta_values, denoising_meta_values=denoising_meta_values,
predicted_corners=predicted_corners,
initial_reference_points=initial_reference_points,
**loss_kwargs, **loss_kwargs,
) )
@@ -2058,6 +2078,8 @@ class RTDetrV2ForObjectDetection(RTDetrV2PreTrainedModel):
intermediate_hidden_states=outputs.intermediate_hidden_states, intermediate_hidden_states=outputs.intermediate_hidden_states,
intermediate_logits=outputs.intermediate_logits, intermediate_logits=outputs.intermediate_logits,
intermediate_reference_points=outputs.intermediate_reference_points, intermediate_reference_points=outputs.intermediate_reference_points,
intermediate_predicted_corners=outputs.intermediate_predicted_corners,
initial_reference_points=outputs.initial_reference_points,
decoder_hidden_states=outputs.decoder_hidden_states, decoder_hidden_states=outputs.decoder_hidden_states,
decoder_attentions=outputs.decoder_attentions, decoder_attentions=outputs.decoder_attentions,
cross_attentions=outputs.cross_attentions, cross_attentions=outputs.cross_attentions,

View File

View File

@@ -0,0 +1,810 @@
# coding = utf-8
# Copyright 2025 The HuggingFace Inc. team. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Testing suite for the PyTorch D-FINE model."""
import inspect
import math
import tempfile
import unittest
from parameterized import parameterized
from transformers import (
DFineConfig,
HGNetV2Config,
is_torch_available,
is_vision_available,
)
from transformers.testing_utils import require_torch, require_torch_gpu, require_vision, slow, torch_device
from transformers.utils import cached_property
if is_torch_available():
import torch
from transformers import DFineForObjectDetection, DFineModel
if is_vision_available():
from PIL import Image
from transformers import RTDetrImageProcessor
from ...test_configuration_common import ConfigTester
from ...test_modeling_common import ModelTesterMixin, _config_zero_init, floats_tensor
from ...test_pipeline_mixin import PipelineTesterMixin
CHECKPOINT = "ustc-community/dfine_s_coco"
class DFineModelTester:
def __init__(
self,
parent,
batch_size=3,
is_training=True,
use_labels=True,
n_targets=3,
num_labels=10,
initializer_range=0.02,
layer_norm_eps=1e-5,
batch_norm_eps=1e-5,
# backbone
backbone_config=None,
# encoder HybridEncoder
encoder_hidden_dim=32,
encoder_in_channels=[128, 256, 512],
feat_strides=[8, 16, 32],
encoder_layers=1,
encoder_ffn_dim=64,
encoder_attention_heads=2,
dropout=0.0,
activation_dropout=0.0,
encode_proj_layers=[2],
positional_encoding_temperature=10000,
encoder_activation_function="gelu",
activation_function="silu",
eval_size=None,
normalize_before=False,
# decoder DFineTransformer
d_model=32,
num_queries=30,
decoder_in_channels=[32, 32, 32],
decoder_ffn_dim=64,
num_feature_levels=3,
decoder_n_points=[3, 6, 3],
decoder_n_levels=3,
decoder_layers=2,
decoder_attention_heads=2,
decoder_activation_function="relu",
attention_dropout=0.0,
num_denoising=0,
label_noise_ratio=0.5,
box_noise_scale=1.0,
learn_initial_query=False,
anchor_image_size=None,
image_size=64,
disable_custom_kernels=True,
with_box_refine=True,
decoder_offset_scale=0.5,
eval_idx=-1,
layer_scale=1,
reg_max=32,
reg_scale=4.0,
depth_mult=0.34,
hidden_expansion=0.5,
):
self.parent = parent
self.batch_size = batch_size
self.num_channels = 3
self.is_training = is_training
self.use_labels = use_labels
self.n_targets = n_targets
self.num_labels = num_labels
self.initializer_range = initializer_range
self.layer_norm_eps = layer_norm_eps
self.batch_norm_eps = batch_norm_eps
self.backbone_config = backbone_config
self.encoder_hidden_dim = encoder_hidden_dim
self.encoder_in_channels = encoder_in_channels
self.feat_strides = feat_strides
self.encoder_layers = encoder_layers
self.encoder_ffn_dim = encoder_ffn_dim
self.encoder_attention_heads = encoder_attention_heads
self.dropout = dropout
self.activation_dropout = activation_dropout
self.encode_proj_layers = encode_proj_layers
self.positional_encoding_temperature = positional_encoding_temperature
self.encoder_activation_function = encoder_activation_function
self.activation_function = activation_function
self.eval_size = eval_size
self.normalize_before = normalize_before
self.d_model = d_model
self.num_queries = num_queries
self.decoder_in_channels = decoder_in_channels
self.decoder_ffn_dim = decoder_ffn_dim
self.num_feature_levels = num_feature_levels
self.decoder_n_points = decoder_n_points
self.decoder_n_levels = decoder_n_levels
self.decoder_layers = decoder_layers
self.decoder_attention_heads = decoder_attention_heads
self.decoder_activation_function = decoder_activation_function
self.attention_dropout = attention_dropout
self.decoder_offset_scale = decoder_offset_scale
self.eval_idx = eval_idx
self.layer_scale = layer_scale
self.reg_max = reg_max
self.reg_scale = reg_scale
self.depth_mult = depth_mult
self.num_denoising = num_denoising
self.label_noise_ratio = label_noise_ratio
self.box_noise_scale = box_noise_scale
self.learn_initial_query = learn_initial_query
self.anchor_image_size = anchor_image_size
self.image_size = image_size
self.disable_custom_kernels = disable_custom_kernels
self.with_box_refine = with_box_refine
self.hidden_expansion = hidden_expansion
self.encoder_seq_length = math.ceil(self.image_size / 32) * math.ceil(self.image_size / 32)
def prepare_config_and_inputs(self):
pixel_values = floats_tensor([self.batch_size, self.num_channels, self.image_size, self.image_size])
pixel_mask = torch.ones([self.batch_size, self.image_size, self.image_size], device=torch_device)
labels = None
if self.use_labels:
# labels is a list of Dict (each Dict being the labels for a given example in the batch)
labels = []
for i in range(self.batch_size):
target = {}
target["class_labels"] = torch.randint(
high=self.num_labels, size=(self.n_targets,), device=torch_device
)
target["boxes"] = torch.rand(self.n_targets, 4, device=torch_device)
labels.append(target)
config = self.get_config()
config.num_labels = self.num_labels
return config, pixel_values, pixel_mask, labels
def get_config(self):
hidden_sizes = [64, 128, 256, 512]
backbone_config = HGNetV2Config(
stage_in_channels=[16, 64, 128, 256],
stage_mid_channels=[16, 32, 64, 128],
stage_out_channels=[64, 128, 256, 512],
stage_num_blocks=[1, 1, 2, 1],
stage_downsample=[False, True, True, True],
stage_light_block=[False, False, True, True],
stage_kernel_size=[3, 3, 5, 5],
stage_numb_of_layers=[3, 3, 3, 3],
embeddings_size=10,
hidden_sizes=hidden_sizes,
depths=[1, 1, 2, 1],
out_features=["stage2", "stage3", "stage4"],
out_indices=[2, 3, 4],
stem_channels=[3, 16, 16],
use_lab=True,
)
return DFineConfig.from_backbone_configs(
backbone_config=backbone_config,
encoder_hidden_dim=self.encoder_hidden_dim,
encoder_in_channels=self.encoder_in_channels,
feat_strides=self.feat_strides,
encoder_layers=self.encoder_layers,
encoder_ffn_dim=self.encoder_ffn_dim,
encoder_attention_heads=self.encoder_attention_heads,
dropout=self.dropout,
activation_dropout=self.activation_dropout,
encode_proj_layers=self.encode_proj_layers,
positional_encoding_temperature=self.positional_encoding_temperature,
encoder_activation_function=self.encoder_activation_function,
activation_function=self.activation_function,
eval_size=self.eval_size,
normalize_before=self.normalize_before,
d_model=self.d_model,
num_queries=self.num_queries,
decoder_in_channels=self.decoder_in_channels,
decoder_ffn_dim=self.decoder_ffn_dim,
num_feature_levels=self.num_feature_levels,
decoder_n_points=self.decoder_n_points,
decoder_n_levels=self.decoder_n_levels,
decoder_layers=self.decoder_layers,
decoder_attention_heads=self.decoder_attention_heads,
decoder_activation_function=self.decoder_activation_function,
decoder_offset_scale=self.decoder_offset_scale,
eval_idx=self.eval_idx,
layer_scale=self.layer_scale,
reg_max=self.reg_max,
reg_scale=self.reg_scale,
depth_mult=self.depth_mult,
attention_dropout=self.attention_dropout,
num_denoising=self.num_denoising,
label_noise_ratio=self.label_noise_ratio,
box_noise_scale=self.box_noise_scale,
learn_initial_query=self.learn_initial_query,
anchor_image_size=self.anchor_image_size,
image_size=self.image_size,
disable_custom_kernels=self.disable_custom_kernels,
with_box_refine=self.with_box_refine,
)
def prepare_config_and_inputs_for_common(self):
config, pixel_values, pixel_mask, labels = self.prepare_config_and_inputs()
inputs_dict = {"pixel_values": pixel_values}
return config, inputs_dict
def create_and_check_d_fine_model(self, config, pixel_values, pixel_mask, labels):
model = DFineModel(config=config)
model.to(torch_device)
model.eval()
result = model(pixel_values=pixel_values, pixel_mask=pixel_mask)
result = model(pixel_values)
self.parent.assertEqual(result.last_hidden_state.shape, (self.batch_size, self.num_queries, self.d_model))
def create_and_check_d_fine_object_detection_head_model(self, config, pixel_values, pixel_mask, labels):
model = DFineForObjectDetection(config=config)
model.to(torch_device)
model.eval()
result = model(pixel_values=pixel_values, pixel_mask=pixel_mask)
result = model(pixel_values)
self.parent.assertEqual(result.logits.shape, (self.batch_size, self.num_queries, self.num_labels))
self.parent.assertEqual(result.pred_boxes.shape, (self.batch_size, self.num_queries, 4))
result = model(pixel_values=pixel_values, pixel_mask=pixel_mask, labels=labels)
self.parent.assertEqual(result.loss.shape, ())
self.parent.assertEqual(result.logits.shape, (self.batch_size, self.num_queries, self.num_labels))
self.parent.assertEqual(result.pred_boxes.shape, (self.batch_size, self.num_queries, 4))
@require_torch
class DFineModelTest(ModelTesterMixin, PipelineTesterMixin, unittest.TestCase):
all_model_classes = (DFineModel, DFineForObjectDetection) if is_torch_available() else ()
pipeline_model_mapping = (
{"image-feature-extraction": DFineModel, "object-detection": DFineForObjectDetection}
if is_torch_available()
else {}
)
is_encoder_decoder = True
test_torchscript = False
test_pruning = False
test_head_masking = False
test_missing_keys = False
test_torch_exportable = True
# special case for head models
def _prepare_for_class(self, inputs_dict, model_class, return_labels=False):
inputs_dict = super()._prepare_for_class(inputs_dict, model_class, return_labels=return_labels)
if return_labels:
if model_class.__name__ == "DFineForObjectDetection":
labels = []
for i in range(self.model_tester.batch_size):
target = {}
target["class_labels"] = torch.ones(
size=(self.model_tester.n_targets,), device=torch_device, dtype=torch.long
)
target["boxes"] = torch.ones(
self.model_tester.n_targets, 4, device=torch_device, dtype=torch.float
)
labels.append(target)
inputs_dict["labels"] = labels
return inputs_dict
def setUp(self):
self.model_tester = DFineModelTester(self)
self.config_tester = ConfigTester(
self,
config_class=DFineConfig,
has_text_modality=False,
common_properties=["hidden_size", "num_attention_heads"],
)
def test_config(self):
self.config_tester.run_common_tests()
def test_d_fine_model(self):
config_and_inputs = self.model_tester.prepare_config_and_inputs()
self.model_tester.create_and_check_d_fine_model(*config_and_inputs)
def test_d_fine_object_detection_head_model(self):
config_and_inputs = self.model_tester.prepare_config_and_inputs()
self.model_tester.create_and_check_d_fine_object_detection_head_model(*config_and_inputs)
@unittest.skip(reason="DFine doesn't work well with `nn.DataParallel")
def test_multi_gpu_data_parallel_forward(self):
pass
@unittest.skip(reason="DFine does not use inputs_embeds")
def test_inputs_embeds(self):
pass
@unittest.skip(reason="DFine does not use test_inputs_embeds_matches_input_ids")
def test_inputs_embeds_matches_input_ids(self):
pass
@unittest.skip(reason="DFine does not support input and output embeddings")
def test_model_get_set_embeddings(self):
pass
@unittest.skip(reason="DFine does not support input and output embeddings")
def test_model_common_attributes(self):
pass
@unittest.skip(reason="DFine does not use token embeddings")
def test_resize_tokens_embeddings(self):
pass
@unittest.skip(reason="Not relevant for the model")
def test_can_init_all_missing_weights(self):
pass
@unittest.skip(reason="Feed forward chunking is not implemented")
def test_feed_forward_chunking(self):
pass
def test_attention_outputs(self):
config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
config.return_dict = True
for model_class in self.all_model_classes:
inputs_dict["output_attentions"] = True
inputs_dict["output_hidden_states"] = False
config.return_dict = True
model = model_class(config)
model.to(torch_device)
model.eval()
with torch.no_grad():
outputs = model(**self._prepare_for_class(inputs_dict, model_class))
attentions = outputs.encoder_attentions
self.assertEqual(len(attentions), self.model_tester.encoder_layers)
# check that output_attentions also work using config
del inputs_dict["output_attentions"]
config.output_attentions = True
model = model_class(config)
model.to(torch_device)
model.eval()
with torch.no_grad():
outputs = model(**self._prepare_for_class(inputs_dict, model_class))
attentions = outputs.encoder_attentions
self.assertEqual(len(attentions), self.model_tester.encoder_layers)
self.assertListEqual(
list(attentions[0].shape[-3:]),
[
self.model_tester.encoder_attention_heads,
self.model_tester.encoder_seq_length,
self.model_tester.encoder_seq_length,
],
)
out_len = len(outputs)
correct_outlen = 15
# loss is at first position
if "labels" in inputs_dict:
correct_outlen += 1 # loss is added to beginning
# Object Detection model returns pred_logits and pred_boxes
if model_class.__name__ == "DFineForObjectDetection":
correct_outlen += 2
self.assertEqual(out_len, correct_outlen)
# decoder attentions
decoder_attentions = outputs.decoder_attentions
self.assertIsInstance(decoder_attentions, (list, tuple))
self.assertEqual(len(decoder_attentions), self.model_tester.decoder_layers)
self.assertListEqual(
list(decoder_attentions[0].shape[-3:]),
[
self.model_tester.decoder_attention_heads,
self.model_tester.num_queries,
self.model_tester.num_queries,
],
)
# cross attentions
cross_attentions = outputs.cross_attentions
self.assertIsInstance(cross_attentions, (list, tuple))
self.assertEqual(len(cross_attentions), self.model_tester.decoder_layers)
self.assertListEqual(
list(cross_attentions[0].shape[-3:]),
[
self.model_tester.num_queries,
self.model_tester.decoder_attention_heads,
self.model_tester.decoder_n_levels * self.model_tester.decoder_n_points
if isinstance(self.model_tester.decoder_n_points, int)
else sum(self.model_tester.decoder_n_points),
],
)
# Check attention is always last and order is fine
inputs_dict["output_attentions"] = True
inputs_dict["output_hidden_states"] = True
model = model_class(config)
model.to(torch_device)
model.eval()
with torch.no_grad():
outputs = model(**self._prepare_for_class(inputs_dict, model_class))
if hasattr(self.model_tester, "num_hidden_states_types"):
added_hidden_states = self.model_tester.num_hidden_states_types
else:
# DFine should maintin encoder_hidden_states output
added_hidden_states = 2
self.assertEqual(out_len + added_hidden_states, len(outputs))
self_attentions = outputs.encoder_attentions
self.assertEqual(len(self_attentions), self.model_tester.encoder_layers)
self.assertListEqual(
list(self_attentions[0].shape[-3:]),
[
self.model_tester.encoder_attention_heads,
self.model_tester.encoder_seq_length,
self.model_tester.encoder_seq_length,
],
)
def test_hidden_states_output(self):
def check_hidden_states_output(inputs_dict, config, model_class):
model = model_class(config)
model.to(torch_device)
model.eval()
with torch.no_grad():
outputs = model(**self._prepare_for_class(inputs_dict, model_class))
hidden_states = outputs.encoder_hidden_states if config.is_encoder_decoder else outputs.hidden_states
expected_num_layers = getattr(
self.model_tester, "expected_num_hidden_layers", len(self.model_tester.encoder_in_channels) - 1
)
self.assertEqual(len(hidden_states), expected_num_layers)
self.assertListEqual(
list(hidden_states[1].shape[-2:]),
[
self.model_tester.image_size // self.model_tester.feat_strides[-1],
self.model_tester.image_size // self.model_tester.feat_strides[-1],
],
)
if config.is_encoder_decoder:
hidden_states = outputs.decoder_hidden_states
expected_num_layers = getattr(
self.model_tester, "expected_num_hidden_layers", self.model_tester.decoder_layers + 1
)
self.assertIsInstance(hidden_states, (list, tuple))
self.assertEqual(len(hidden_states), expected_num_layers)
self.assertListEqual(
list(hidden_states[0].shape[-2:]),
[self.model_tester.num_queries, self.model_tester.d_model],
)
config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
for model_class in self.all_model_classes:
inputs_dict["output_hidden_states"] = True
check_hidden_states_output(inputs_dict, config, model_class)
# check that output_hidden_states also work using config
del inputs_dict["output_hidden_states"]
config.output_hidden_states = True
check_hidden_states_output(inputs_dict, config, model_class)
def test_retain_grad_hidden_states_attentions(self):
config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
config.output_hidden_states = True
config.output_attentions = True
model_class = self.all_model_classes[0]
model = model_class(config)
model.to(torch_device)
inputs = self._prepare_for_class(inputs_dict, model_class)
outputs = model(**inputs)
# we take the first output since last_hidden_state is the first item
output = outputs[0]
encoder_hidden_states = outputs.encoder_hidden_states[0]
encoder_attentions = outputs.encoder_attentions[0]
encoder_hidden_states.retain_grad()
encoder_attentions.retain_grad()
decoder_attentions = outputs.decoder_attentions[0]
decoder_attentions.retain_grad()
cross_attentions = outputs.cross_attentions[0]
cross_attentions.retain_grad()
output.flatten()[0].backward(retain_graph=True)
self.assertIsNotNone(encoder_hidden_states.grad)
self.assertIsNotNone(encoder_attentions.grad)
self.assertIsNotNone(decoder_attentions.grad)
self.assertIsNotNone(cross_attentions.grad)
def test_forward_signature(self):
config, _ = self.model_tester.prepare_config_and_inputs_for_common()
for model_class in self.all_model_classes:
model = model_class(config)
signature = inspect.signature(model.forward)
arg_names = [*signature.parameters.keys()]
expected_arg_names = ["pixel_values"]
self.assertListEqual(arg_names[:1], expected_arg_names)
def test_different_timm_backbone(self):
config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
# let's pick a random timm backbone
config.encoder_in_channels = [24, 40, 432]
config.backbone = "tf_mobilenetv3_small_075"
config.backbone_config = None
config.use_timm_backbone = True
config.backbone_kwargs = {"out_indices": [2, 3, 4]}
for model_class in self.all_model_classes:
model = model_class(config)
model.to(torch_device)
model.eval()
with torch.no_grad():
outputs = model(**self._prepare_for_class(inputs_dict, model_class))
if model_class.__name__ == "DFineForObjectDetection":
expected_shape = (
self.model_tester.batch_size,
self.model_tester.num_queries,
self.model_tester.num_labels,
)
self.assertEqual(outputs.logits.shape, expected_shape)
# Confirm out_indices was propogated to backbone
self.assertEqual(len(model.model.backbone.intermediate_channel_sizes), 3)
else:
# Confirm out_indices was propogated to backbone
self.assertEqual(len(model.backbone.intermediate_channel_sizes), 3)
self.assertTrue(outputs)
def test_hf_backbone(self):
config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
# Load a pretrained HF checkpoint as backbone
config.backbone = "microsoft/resnet-18"
config.backbone_config = None
config.use_timm_backbone = False
config.use_pretrained_backbone = True
config.backbone_kwargs = {"out_indices": [2, 3, 4]}
for model_class in self.all_model_classes:
model = model_class(config)
model.to(torch_device)
model.eval()
with torch.no_grad():
outputs = model(**self._prepare_for_class(inputs_dict, model_class))
if model_class.__name__ == "DFineForObjectDetection":
expected_shape = (
self.model_tester.batch_size,
self.model_tester.num_queries,
self.model_tester.num_labels,
)
self.assertEqual(outputs.logits.shape, expected_shape)
# Confirm out_indices was propogated to backbone
self.assertEqual(len(model.model.backbone.intermediate_channel_sizes), 3)
else:
# Confirm out_indices was propogated to backbone
self.assertEqual(len(model.backbone.intermediate_channel_sizes), 3)
self.assertTrue(outputs)
def test_initialization(self):
config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
configs_no_init = _config_zero_init(config)
configs_no_init.initializer_bias_prior_prob = 0.2
bias_value = -1.3863 # log_e ((1 - 0.2) / 0.2)
failed_cases = []
for model_class in self.all_model_classes:
model = model_class(config=configs_no_init)
# Skip the check for the backbone
for name, module in model.named_modules():
if module.__class__.__name__ == "DFineConvEncoder":
backbone_params = [f"{name}.{key}" for key in module.state_dict().keys()]
break
for name, param in model.named_parameters():
if param.requires_grad:
if ("class_embed" in name and "bias" in name) or "enc_score_head.bias" in name:
bias_tensor = torch.full_like(param.data, bias_value)
try:
torch.testing.assert_close(param.data, bias_tensor, atol=1e-4, rtol=1e-4)
except AssertionError:
failed_cases.append(
f"Parameter {name} of model {model_class} seems not properly initialized. "
f"Biases should be initialized to {bias_value}, got {param.data}"
)
elif (
"level_embed" in name
or "sampling_offsets.bias" in name
or "value_proj" in name
or "output_proj" in name
or "reference_points" in name
or "enc_score_head.weight" in name
or ("class_embed" in name and "weight" in name)
or name in backbone_params
):
continue
else:
mean = param.data.mean()
round_mean = (mean * 1e9).round() / 1e9
round_mean = round_mean.item()
if round_mean not in [0.0, 1.0]:
failed_cases.append(
f"Parameter {name} of model {model_class} seems not properly initialized. "
f"Mean is {round_mean}, but should be in [0, 1]"
)
message = "\n" + "\n".join(failed_cases)
self.assertTrue(not failed_cases, message)
@parameterized.expand(["float32", "float16", "bfloat16"])
@require_torch_gpu
@slow
def test_inference_with_different_dtypes(self, torch_dtype_str):
torch_dtype = {
"float32": torch.float32,
"float16": torch.float16,
"bfloat16": torch.bfloat16,
}[torch_dtype_str]
config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
for model_class in self.all_model_classes:
model = model_class(config)
model.to(torch_device).to(torch_dtype)
model.eval()
for key, tensor in inputs_dict.items():
if tensor.dtype == torch.float32:
inputs_dict[key] = tensor.to(torch_dtype)
with torch.no_grad():
_ = model(**self._prepare_for_class(inputs_dict, model_class))
@parameterized.expand(["float32", "float16", "bfloat16"])
@require_torch_gpu
@slow
def test_inference_equivalence_for_static_and_dynamic_anchors(self, torch_dtype_str):
torch_dtype = {
"float32": torch.float32,
"float16": torch.float16,
"bfloat16": torch.bfloat16,
}[torch_dtype_str]
config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
h, w = inputs_dict["pixel_values"].shape[-2:]
# convert inputs to the desired dtype
for key, tensor in inputs_dict.items():
if tensor.dtype == torch.float32:
inputs_dict[key] = tensor.to(torch_dtype)
for model_class in self.all_model_classes:
with tempfile.TemporaryDirectory() as tmpdirname:
model_class(config).save_pretrained(tmpdirname)
model_static = model_class.from_pretrained(
tmpdirname, anchor_image_size=[h, w], device_map=torch_device, torch_dtype=torch_dtype
).eval()
model_dynamic = model_class.from_pretrained(
tmpdirname, anchor_image_size=None, device_map=torch_device, torch_dtype=torch_dtype
).eval()
self.assertIsNotNone(model_static.config.anchor_image_size)
self.assertIsNone(model_dynamic.config.anchor_image_size)
with torch.no_grad():
outputs_static = model_static(**self._prepare_for_class(inputs_dict, model_class))
outputs_dynamic = model_dynamic(**self._prepare_for_class(inputs_dict, model_class))
torch.testing.assert_close(
outputs_static.last_hidden_state, outputs_dynamic.last_hidden_state, rtol=1e-4, atol=1e-4
)
TOLERANCE = 1e-4
# We will verify our results on an image of cute cats
def prepare_img():
image = Image.open("./tests/fixtures/tests_samples/COCO/000000039769.png")
return image
@require_torch
@require_vision
class DFineModelIntegrationTest(unittest.TestCase):
@cached_property
def default_image_processor(self):
return RTDetrImageProcessor.from_pretrained(CHECKPOINT) if is_vision_available() else None
def test_inference_object_detection_head(self):
model = DFineForObjectDetection.from_pretrained(CHECKPOINT).to(torch_device)
image_processor = self.default_image_processor
image = prepare_img()
inputs = image_processor(images=image, return_tensors="pt").to(torch_device)
with torch.no_grad():
outputs = model(**inputs)
expected_shape_logits = torch.Size((1, 300, model.config.num_labels))
self.assertEqual(outputs.logits.shape, expected_shape_logits)
expected_logits = torch.tensor(
[
[-3.8097816, -4.7724586, -5.994499],
[-5.2974715, -9.499067, -6.1653666],
[-5.3502765, -3.9530406, -6.3630295],
]
).to(torch_device)
expected_boxes = torch.tensor(
[
[0.7677696, 0.41479152, 0.46441072],
[0.16912134, 0.19869131, 0.2123824],
[0.2581653, 0.54818195, 0.47512347],
]
).to(torch_device)
torch.testing.assert_close(outputs.logits[0, :3, :3], expected_logits, atol=1e-4, rtol=1e-4)
expected_shape_boxes = torch.Size((1, 300, 4))
self.assertEqual(outputs.pred_boxes.shape, expected_shape_boxes)
torch.testing.assert_close(outputs.pred_boxes[0, :3, :3], expected_boxes, atol=1e-4, rtol=1e-4)
# verify postprocessing
results = image_processor.post_process_object_detection(
outputs, threshold=0.0, target_sizes=[image.size[::-1]]
)[0]
expected_scores = torch.tensor([0.9642, 0.9542, 0.9536, 0.8548], device=torch_device)
expected_labels = [15, 65, 15, 57]
expected_slice_boxes = torch.tensor(
[
[1.3186283e01, 5.4130211e01, 3.1726535e02, 4.7212445e02],
[4.0275269e01, 7.2975174e01, 1.7620003e02, 1.1776848e02],
[3.4276117e02, 2.3427944e01, 6.3998401e02, 3.7477191e02],
[5.8418274e-01, 1.1794567e00, 6.3933154e02, 4.7485995e02],
],
device=torch_device,
)
torch.testing.assert_close(results["scores"][:4], expected_scores, atol=1e-3, rtol=1e-4)
self.assertSequenceEqual(results["labels"][:4].tolist(), expected_labels)
torch.testing.assert_close(results["boxes"][:4], expected_slice_boxes[:4], atol=1e-3, rtol=1e-4)

View File

View File

@@ -0,0 +1,286 @@
# coding=utf-8
# Copyright 2025 The HuggingFace Inc. team. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
import torch
from torch import nn
from transformers import HGNetV2Config
from transformers.testing_utils import require_torch, torch_device
from transformers.utils.import_utils import is_torch_available
from ...test_backbone_common import BackboneTesterMixin
from ...test_modeling_common import ModelTesterMixin, floats_tensor, ids_tensor
from ...test_pipeline_mixin import PipelineTesterMixin
if is_torch_available():
from transformers import HGNetV2Backbone, HGNetV2ForImageClassification
class HGNetV2ModelTester:
def __init__(
self,
parent,
batch_size=3,
image_size=32,
num_channels=3,
embeddings_size=10,
hidden_sizes=[64, 128, 256, 512],
stage_in_channels=[16, 64, 128, 256],
stage_mid_channels=[16, 32, 64, 128],
stage_out_channels=[64, 128, 256, 512],
stage_num_blocks=[1, 1, 2, 1],
stage_downsample=[False, True, True, True],
stage_light_block=[False, False, True, True],
stage_kernel_size=[3, 3, 5, 5],
stage_numb_of_layers=[3, 3, 3, 3],
stem_channels=[3, 16, 16],
depths=[1, 1, 2, 1],
is_training=True,
use_labels=True,
hidden_act="relu",
num_labels=3,
scope=None,
out_features=["stage2", "stage3", "stage4"],
out_indices=[2, 3, 4],
):
self.parent = parent
self.batch_size = batch_size
self.image_size = image_size
self.num_channels = num_channels
self.embeddings_size = embeddings_size
self.hidden_sizes = hidden_sizes
self.stage_in_channels = stage_in_channels
self.stage_mid_channels = stage_mid_channels
self.stage_out_channels = stage_out_channels
self.stage_num_blocks = stage_num_blocks
self.stage_downsample = stage_downsample
self.stage_light_block = stage_light_block
self.stage_kernel_size = stage_kernel_size
self.stage_numb_of_layers = stage_numb_of_layers
self.stem_channels = stem_channels
self.depths = depths
self.is_training = is_training
self.use_labels = use_labels
self.hidden_act = hidden_act
self.num_labels = num_labels
self.scope = scope
self.num_stages = len(hidden_sizes)
self.out_features = out_features
self.out_indices = out_indices
def prepare_config_and_inputs(self):
pixel_values = floats_tensor([self.batch_size, self.num_channels, self.image_size, self.image_size])
labels = None
if self.use_labels:
labels = ids_tensor([self.batch_size], self.num_labels)
config = self.get_config()
return config, pixel_values, labels
def get_config(self):
return HGNetV2Config(
num_channels=self.num_channels,
embeddings_size=self.embeddings_size,
hidden_sizes=self.hidden_sizes,
stage_in_channels=self.stage_in_channels,
stage_mid_channels=self.stage_mid_channels,
stage_out_channels=self.stage_out_channels,
stage_num_blocks=self.stage_num_blocks,
stage_downsample=self.stage_downsample,
stage_light_block=self.stage_light_block,
stage_kernel_size=self.stage_kernel_size,
stage_numb_of_layers=self.stage_numb_of_layers,
stem_channels=self.stem_channels,
depths=self.depths,
hidden_act=self.hidden_act,
num_labels=self.num_labels,
out_features=self.out_features,
out_indices=self.out_indices,
)
def create_and_check_backbone(self, config, pixel_values, labels):
model = HGNetV2Backbone(config=config)
model.to(torch_device)
model.eval()
result = model(pixel_values)
# verify feature maps
self.parent.assertEqual(len(result.feature_maps), len(config.out_features))
self.parent.assertListEqual(list(result.feature_maps[0].shape), [self.batch_size, self.hidden_sizes[1], 4, 4])
# verify channels
self.parent.assertEqual(len(model.channels), len(config.out_features))
self.parent.assertListEqual(model.channels, config.hidden_sizes[1:])
# verify backbone works with out_features=None
config.out_features = None
model = HGNetV2Backbone(config=config)
model.to(torch_device)
model.eval()
result = model(pixel_values)
# verify feature maps
self.parent.assertEqual(len(result.feature_maps), 1)
self.parent.assertListEqual(list(result.feature_maps[0].shape), [self.batch_size, self.hidden_sizes[-1], 1, 1])
# verify channels
self.parent.assertEqual(len(model.channels), 1)
self.parent.assertListEqual(model.channels, [config.hidden_sizes[-1]])
def create_and_check_for_image_classification(self, config, pixel_values, labels):
config.num_labels = self.num_labels
model = HGNetV2ForImageClassification(config)
model.to(torch_device)
model.eval()
result = model(pixel_values, labels=labels)
self.parent.assertEqual(result.logits.shape, (self.batch_size, self.num_labels))
def prepare_config_and_inputs_for_common(self):
config_and_inputs = self.prepare_config_and_inputs()
config, pixel_values, labels = config_and_inputs
inputs_dict = {"pixel_values": pixel_values}
return config, inputs_dict
@require_torch
class RTDetrResNetBackboneTest(BackboneTesterMixin, unittest.TestCase):
all_model_classes = (HGNetV2Backbone,) if is_torch_available() else ()
has_attentions = False
config_class = HGNetV2Config
def setUp(self):
self.model_tester = HGNetV2ModelTester(self)
@require_torch
class HGNetV2ForImageClassificationTest(ModelTesterMixin, PipelineTesterMixin, unittest.TestCase):
"""
Here we also overwrite some tests of test_modeling_common.py, as TextNet does not use input_ids, inputs_embeds,
attention_mask and seq_length.
"""
all_model_classes = (HGNetV2ForImageClassification, HGNetV2Backbone) if is_torch_available() else ()
pipeline_model_mapping = {"image-classification": HGNetV2ForImageClassification} if is_torch_available() else {}
fx_compatible = False
test_pruning = False
test_resize_embeddings = False
test_head_masking = False
test_torch_exportable = True
has_attentions = False
def setUp(self):
self.model_tester = HGNetV2ModelTester(self)
@unittest.skip(reason="Does not work on the tiny model.")
def test_model_parallelism(self):
super().test_model_parallelism()
@unittest.skip(reason="HGNetV2 does not output attentions")
def test_attention_outputs(self):
pass
@unittest.skip(reason="HGNetV2 does not have input/output embeddings")
def test_model_get_set_embeddings(self):
pass
@unittest.skip(reason="HGNetV2 does not use inputs_embeds")
def test_inputs_embeds(self):
pass
@unittest.skip(reason="HGNetV2 does not support input and output embeddings")
def test_model_common_attributes(self):
pass
@unittest.skip(reason="HGNetV2 does not have a model")
def test_model(self):
pass
@unittest.skip(reason="Not relevant for the model")
def test_can_init_all_missing_weights(self):
pass
def test_backbone(self):
config_and_inputs = self.model_tester.prepare_config_and_inputs()
self.model_tester.create_and_check_backbone(*config_and_inputs)
def test_initialization(self):
config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
for model_class in self.all_model_classes:
model = model_class(config=config)
for name, module in model.named_modules():
if isinstance(module, (nn.BatchNorm2d, nn.GroupNorm)):
self.assertTrue(
torch.all(module.weight == 1),
msg=f"Parameter {name} of model {model_class} seems not properly initialized",
)
self.assertTrue(
torch.all(module.bias == 0),
msg=f"Parameter {name} of model {model_class} seems not properly initialized",
)
def test_hidden_states_output(self):
def check_hidden_states_output(inputs_dict, config, model_class):
model = model_class(config)
model.to(torch_device)
model.eval()
with torch.no_grad():
outputs = model(**self._prepare_for_class(inputs_dict, model_class))
hidden_states = outputs.encoder_hidden_states if config.is_encoder_decoder else outputs.hidden_states
self.assertEqual(len(hidden_states), self.model_tester.num_stages + 1)
self.assertListEqual(
list(hidden_states[0].shape[-2:]),
[self.model_tester.image_size // 4, self.model_tester.image_size // 4],
)
config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
layers_type = ["preactivation", "bottleneck"]
for model_class in self.all_model_classes:
for layer_type in layers_type:
config.layer_type = layer_type
inputs_dict["output_hidden_states"] = True
check_hidden_states_output(inputs_dict, config, model_class)
# check that output_hidden_states also work using config
del inputs_dict["output_hidden_states"]
config.output_hidden_states = True
check_hidden_states_output(inputs_dict, config, model_class)
@unittest.skip(reason="Retain_grad is not supposed to be tested")
def test_retain_grad_hidden_states_attentions(self):
pass
@unittest.skip(reason="TextNet does not use feedforward chunking")
def test_feed_forward_chunking(self):
pass
def test_for_image_classification(self):
config_and_inputs = self.model_tester.prepare_config_and_inputs()
self.model_tester.create_and_check_for_image_classification(*config_and_inputs)
@unittest.skip(reason="HGNetV2 does not use model")
def test_model_from_pretrained(self):
pass

View File

@@ -183,6 +183,22 @@ SPECIAL_CASES_TO_ALLOW = {
"giou_loss_coefficient", "giou_loss_coefficient",
"mask_loss_coefficient", "mask_loss_coefficient",
], ],
"DFineConfig": [
"eos_coefficient",
"focal_loss_alpha",
"focal_loss_gamma",
"matcher_alpha",
"matcher_bbox_cost",
"matcher_class_cost",
"matcher_gamma",
"matcher_giou_cost",
"use_focal_loss",
"weight_loss_bbox",
"weight_loss_giou",
"weight_loss_vfl",
"weight_loss_fgl",
"weight_loss_ddf",
],
"GroundingDinoConfig": [ "GroundingDinoConfig": [
"bbox_cost", "bbox_cost",
"bbox_loss_coefficient", "bbox_loss_coefficient",