diff --git a/optimum/utils/normalized_config.py b/optimum/utils/normalized_config.py index 21470cb61f..c1a1c8b60b 100644 --- a/optimum/utils/normalized_config.py +++ b/optimum/utils/normalized_config.py @@ -128,9 +128,15 @@ class NormalizedTextAndVisionConfig(NormalizedTextConfig, NormalizedVisionConfig def __getattr__(self, attr_name): if self.TEXT_CONFIG is not None and attr_name.upper() in dir(NormalizedTextConfig): - attr_name = f"{self.TEXT_CONFIG}.{attr_name}" + # Resolve through the normalized name (e.g. NUM_LAYERS -> "num_hidden_layers") + # before prefixing, not the raw accessor name - otherwise an accessor whose + # normalized name differs from its underlying config attribute (num_layers vs. + # num_hidden_layers) looks up the wrong name on the nested sub-config. + mapped_name = getattr(self, attr_name.upper(), attr_name) + attr_name = f"{self.TEXT_CONFIG}.{mapped_name}" elif self.VISION_CONFIG is not None and attr_name.upper() in dir(NormalizedVisionConfig): - attr_name = f"{self.VISION_CONFIG}.{attr_name}" + mapped_name = getattr(self, attr_name.upper(), attr_name) + attr_name = f"{self.VISION_CONFIG}.{mapped_name}" return super().__getattr__(attr_name) @@ -235,7 +241,6 @@ class NormalizedConfigManager: 'levit', 'mobilebert', 'mobilevit', - 'owlv2', 'owlvit', 'perceiver', 'roformer', @@ -292,6 +297,7 @@ class NormalizedConfigManager: "olmo": NormalizedTextConfig, "olmo2": NormalizedTextConfig, "opt": NormalizedTextConfig, + "owlv2": Pix2StructNormalizedTextConfig, "pegasus": BartLikeNormalizedTextConfig, "pix2struct": Pix2StructNormalizedTextConfig, "phi": NormalizedTextConfig, diff --git a/tests/utils/test_normalized_config.py b/tests/utils/test_normalized_config.py new file mode 100644 index 0000000000..0084c496d1 --- /dev/null +++ b/tests/utils/test_normalized_config.py @@ -0,0 +1,48 @@ +# coding=utf-8 +# Copyright 2022 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 unittest + +from transformers import Owlv2Config, Pix2StructConfig + +from optimum.utils.normalized_config import NormalizedConfigManager, Pix2StructNormalizedTextConfig + + +class NormalizedConfigManagerTest(unittest.TestCase): + def test_owlv2_is_registered(self): + config_class = NormalizedConfigManager.get_normalized_config_class("owlv2") + self.assertIs(config_class, Pix2StructNormalizedTextConfig) + + def test_owlv2_normalizes_expected_attributes(self): + # Same dual text/vision encoder shape as GroupViT/OwlViT/Pix2Struct. OwlV2's + # text_config only has num_hidden_layers, not a num_layers alias, so this + # also exercises the NormalizedTextAndVisionConfig.__getattr__ fix. + config = Owlv2Config() + normalized_config_class = NormalizedConfigManager.get_normalized_config_class("owlv2") + normalized_config = normalized_config_class(config) + + self.assertEqual(normalized_config.hidden_size, config.text_config.hidden_size) + self.assertEqual(normalized_config.num_attention_heads, config.text_config.num_attention_heads) + self.assertEqual(normalized_config.num_layers, config.text_config.num_hidden_layers) + self.assertEqual(normalized_config.image_size, config.vision_config.image_size) + self.assertEqual(normalized_config.num_channels, config.vision_config.num_channels) + + def test_pix2struct_num_layers_unaffected(self): + config = Pix2StructConfig() + normalized_config = Pix2StructNormalizedTextConfig(config) + + self.assertEqual(normalized_config.num_layers, config.text_config.num_layers) + self.assertEqual(normalized_config.hidden_size, config.text_config.hidden_size) + self.assertEqual(normalized_config.num_attention_heads, config.text_config.num_attention_heads)