Transformers documentation
Конфигурации для каждого слоя
Конфигурации для каждого слоя
Некоторые контрольные точки гетерогенны (не имеют однородной структуры по слоям). Более малый MLP в одном слое, меньшее количество ключевых и значимых головок в другом или иной макет в выбранных слоях означают, что единая глобальная конфигурация не описывает стек точно.
Используйте per_layer_config в PreTrainedConfig, чтобы фиксировать эти различия при создании или проверке конфигурации, а также когда код модели будет их использовать. Каждая запись хранит только то, что отличается от глобальной конфигурации, остальное наследуется.
Гетерогенные конфигурации — это мощная возможность. Если гетерогенная компоновка станет распространённой или преобладающей архитектурой, мы будем стремиться явно моделировать её в реализации архитектуры, а не полагаться на
per_layer_config. При наличии явной архитектуры отдавайте ей предпочтение.
Модели, перечисленные ниже, представляют собой гетерогенные контрольные точки. Слои в стеке не являются однородными. Они используют выделенную архитектуру с block_configs и собственным model_type, а не per_layer_config в стандартной архитектуре.
Определение переопределений для каждого слоя
Передайте per_layer_config в LlamaConfig как отображение индексов слоёв на переопределения атрибутов. Индексы слоёв нумеруются с нуля. Необходимо указать только те атрибуты, которые отличаются от глобальной конфигурации.
per_layer_config фиксирует и разрешает значения конфигурации. Сам по себе он не изменяет модули, которые создаёт модель, и не влияет на то, как эти модули выполняются. Применение переопределения размера или skip требует, чтобы код модели читал разрешённую по-слойную конфигурацию при построении или выполнении каждого слоя. Текущая LlamaModel создаёт каждый LlamaDecoderLayer с глобальной конфигурацией, поэтому записи skip ниже остаются значениями конфигурации, а не удаляют модули после from_pretrained.
В следующем примере записываются переопределения для четырёх слоёв: слой 5 использует меньший MLP, слой 11 — меньшее количество ключевых и значимых головок, а слои 23 и 27 записывают значения skip для архитектур, которые их поддерживают.
from transformers import LlamaConfig
config = LlamaConfig(
hidden_size=4096,
intermediate_size=14336,
num_hidden_layers=32,
num_attention_heads=32,
num_key_value_heads=8,
per_layer_config={
# Use a smaller MLP in one layer.
5: {"intermediate_size": 8192},
# Use fewer key-value heads in another layer.
11: {"num_key_value_heads": 4},
# Record a request to skip the MLP in architectures that support it.
23: {"skip": ["mlp"]},
# Record a request to skip attention in architectures that support it.
27: {"skip": ["attention"]},
},
)Подмодули, которые архитектура может пропустить (например, "mlp" и "attention"), определяются для каждой архитектуры. skip принимает список, поэтому слой может зафиксировать более одного переопределения подмодуля.
Обращение к config.per_layer_config[layer_idx] возвращает разрешённую конфигурацию слоя. Разрешённая конфигурация объединяет глобальную конфигурацию с переопределениями для данного слоя.
# Layer 0 does not define overrides, so it inherits the global values.
config.per_layer_config[0].intermediate_size
# 14336
config.per_layer_config[0].num_key_value_heads
# 8
# Layer 5 overrides the MLP intermediate size.
config.per_layer_config[5].intermediate_size
# 8192
# Layer 11 overrides the number of key-value heads.
config.per_layer_config[11].num_key_value_heads
# 4
# Layer 23 records an MLP skip.
config.per_layer_config[23].skip
# ["mlp"]
# Layer 27 records an attention skip.
config.per_layer_config[27].skip
# ["attention"]Конфигурации, использующие per_layer_config, поддерживают тот же цикл save_pretrained() и from_pretrained(), что и другие конфигурации.
Каждая архитектура определяет в своём коде, какие атрибуты она использует на уровне слоя. per_layer_config предоставляет механизм для записи этих различий на уровне слоя и их разрешения относительно глобальной конфигурации.
Доступ к глобальным атрибутам
Атрибут с переопределениями для отдельных слоёв не имеет единого значения для всей модели. num_key_value_heads может быть 8 в большинстве слоёв и 4 в выбранных слоях. Чтение config.num_key_value_heads вне контекста слоя неоднозначно.
По умолчанию такой доступ вызывает AmbiguousGlobalPerLayerAttributeError и указывает на config.per_layer_config[layer_idx]. Атрибут по-прежнему существует в глобальной конфигурации, поэтому это не AttributeError. Чтение этого глобального значения без индекса слоя всё равно является ошибкой. Код, создающий кэш ключей и значений на основе глобального num_key_value_heads, будет неверно рассчитывать размеры для неправильных слоёв.
Устанавливайте allow_global_per_layer_attribute_access=True только в том случае, если вам намеренно необходим глобальный fallback и вы готовы работать с неоднородными конфигурациями. В этом случае глобальный доступ разрешён. Предупреждение выводится один раз.
config = LlamaConfig(
hidden_size=4096,
intermediate_size=14336,
num_hidden_layers=32,
num_attention_heads=32,
num_key_value_heads=8,
allow_global_per_layer_attribute_access=True,
per_layer_config={
11: {"num_key_value_heads": 4},
},
)
config.num_key_value_heads
# 8
# Emits a one-time warning because num_key_value_heads has a per-layer override.Сериализация
per_layer_config по умолчанию сериализуется разреженно, и слои без переопределений пропускаются. Переопределённые атрибуты, совпадающие с глобальным значением, также пропускаются.
from transformers import LlamaConfig
config = LlamaConfig(
hidden_size=4096,
intermediate_size=14336,
num_hidden_layers=4,
num_attention_heads=32,
num_key_value_heads=8,
per_layer_config={
0: {"num_key_value_heads": 8},
2: {"num_key_value_heads": 4},
},
)
config.to_dict()["per_layer_config"]
# {"2": {"num_key_value_heads": 4}}Установите serialize_explicit_per_layer_config=True, чтобы включить в per_layer_config все слои для представленных в нём атрибутов. Это упрощает проверку структуры слоёв, когда некоторые значения всё ещё совпадают с глобальной конфигурацией.
explicit_config = LlamaConfig(
hidden_size=4096,
intermediate_size=14336,
num_hidden_layers=4,
num_attention_heads=32,
num_key_value_heads=8,
serialize_explicit_per_layer_config=True,
per_layer_config={
0: {"num_key_value_heads": 8},
2: {"num_key_value_heads": 4},
},
)
serialized_per_layer_config = explicit_config.to_dict()["per_layer_config"]
serialized_per_layer_config
# {
# "0": {"num_key_value_heads": 8},
# "1": {"num_key_value_heads": 8},
# "2": {"num_key_value_heads": 4},
# "3": {"num_key_value_heads": 8},
# }Используйте разреженную сериализацию для компактных конфигураций, а явную сериализацию — когда для читаемости или работы с инструментами требуется полная поуровневая структура.
Update on GitHub