mirror of
https://github.com/pese-git/llm-arch-research.git
synced 2026-01-26 22:19:16 +00:00
Рефакторинг: единообразие оформления кода (пробелы, кавычки, пустые строки), без изменения логики по всему проекту.
This commit is contained in:
@@ -6,12 +6,12 @@ import torch
|
||||
import torch.nn as nn
|
||||
from typing import Optional, Tuple, Union, List
|
||||
from transformers import (
|
||||
PreTrainedModel,
|
||||
PreTrainedModel,
|
||||
GPT2LMHeadModel,
|
||||
GPT2Config,
|
||||
GenerationConfig,
|
||||
LogitsProcessorList,
|
||||
StoppingCriteriaList
|
||||
StoppingCriteriaList,
|
||||
)
|
||||
from transformers.modeling_outputs import CausalLMOutputWithCrossAttentions
|
||||
|
||||
@@ -24,38 +24,39 @@ class HFGPTAdapter(PreTrainedModel):
|
||||
Адаптер для модели GPT из библиотеки llm.
|
||||
Позволяет использовать кастомные GPT модели с HuggingFace Transformers.
|
||||
"""
|
||||
|
||||
config_class = HFPretrainedConfig
|
||||
|
||||
|
||||
def __init__(self, config: HFPretrainedConfig, llm_model: Optional[GPT] = None):
|
||||
"""
|
||||
Инициализация адаптера.
|
||||
|
||||
|
||||
Args:
|
||||
config: Конфигурация HuggingFace
|
||||
llm_model: Опционально, предварительно созданная модель llm
|
||||
"""
|
||||
super().__init__(config)
|
||||
|
||||
|
||||
# Преобразуем HF конфигурацию в формат llm
|
||||
llm_config = self._hf_to_llm_config(config)
|
||||
|
||||
|
||||
# Создаем или используем переданную модель
|
||||
if llm_model is None:
|
||||
self.llm_model = GPT(llm_config)
|
||||
else:
|
||||
self.llm_model = llm_model
|
||||
|
||||
|
||||
# Устанавливаем веса если они есть в конфигурации
|
||||
if hasattr(config, 'state_dict') and config.state_dict is not None:
|
||||
if hasattr(config, "state_dict") and config.state_dict is not None:
|
||||
self.llm_model.load_state_dict(config.state_dict)
|
||||
|
||||
|
||||
def _hf_to_llm_config(self, hf_config: HFPretrainedConfig) -> dict:
|
||||
"""
|
||||
Преобразует конфигурацию HF в формат llm.
|
||||
|
||||
|
||||
Args:
|
||||
hf_config: Конфигурация HuggingFace
|
||||
|
||||
|
||||
Returns:
|
||||
dict: Конфигурация для llm модели
|
||||
"""
|
||||
@@ -67,7 +68,7 @@ class HFGPTAdapter(PreTrainedModel):
|
||||
"max_position_embeddings": hf_config.max_position_embeddings,
|
||||
"dropout": hf_config.hidden_dropout_prob,
|
||||
}
|
||||
|
||||
|
||||
def forward(
|
||||
self,
|
||||
input_ids: Optional[torch.Tensor] = None,
|
||||
@@ -78,11 +79,11 @@ class HFGPTAdapter(PreTrainedModel):
|
||||
output_attentions: Optional[bool] = None,
|
||||
output_hidden_states: Optional[bool] = None,
|
||||
return_dict: Optional[bool] = None,
|
||||
**kwargs
|
||||
**kwargs,
|
||||
) -> Union[Tuple, CausalLMOutputWithCrossAttentions]:
|
||||
"""
|
||||
Прямой проход модели.
|
||||
|
||||
|
||||
Args:
|
||||
input_ids: Входные токены [batch_size, seq_len]
|
||||
attention_mask: Маска внимания [batch_size, seq_len]
|
||||
@@ -92,38 +93,39 @@ class HFGPTAdapter(PreTrainedModel):
|
||||
output_attentions: Возвращать веса внимания
|
||||
output_hidden_states: Возвращать скрытые состояния
|
||||
return_dict: Возвращать словарь вместо кортежа
|
||||
|
||||
|
||||
Returns:
|
||||
CausalLMOutputWithCrossAttentions или кортеж
|
||||
"""
|
||||
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
||||
|
||||
return_dict = (
|
||||
return_dict if return_dict is not None else self.config.use_return_dict
|
||||
)
|
||||
|
||||
# Основной forward pass
|
||||
outputs = self.llm_model(input_ids)
|
||||
if isinstance(outputs, tuple):
|
||||
logits = outputs[0]
|
||||
else:
|
||||
logits = outputs
|
||||
|
||||
|
||||
loss = None
|
||||
if labels is not None:
|
||||
# Сдвигаем логиты и метки для языкового моделирования
|
||||
shift_logits = logits[..., :-1, :].contiguous()
|
||||
shift_labels = labels[..., 1:].contiguous()
|
||||
|
||||
|
||||
# Вычисляем cross-entropy loss
|
||||
loss_fct = nn.CrossEntropyLoss()
|
||||
loss = loss_fct(
|
||||
shift_logits.view(-1, shift_logits.size(-1)),
|
||||
shift_labels.view(-1)
|
||||
shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1)
|
||||
)
|
||||
|
||||
|
||||
if not return_dict:
|
||||
output = (logits,)
|
||||
if loss is not None:
|
||||
output = (loss,) + output
|
||||
return output
|
||||
|
||||
|
||||
return CausalLMOutputWithCrossAttentions(
|
||||
loss=loss,
|
||||
logits=logits,
|
||||
@@ -132,30 +134,27 @@ class HFGPTAdapter(PreTrainedModel):
|
||||
attentions=None,
|
||||
cross_attentions=None,
|
||||
)
|
||||
|
||||
|
||||
def prepare_inputs_for_generation(
|
||||
self,
|
||||
input_ids: torch.Tensor,
|
||||
past_key_values: Optional[Tuple] = None,
|
||||
**kwargs
|
||||
self, input_ids: torch.Tensor, past_key_values: Optional[Tuple] = None, **kwargs
|
||||
) -> dict:
|
||||
"""
|
||||
Подготавливает входные данные для генерации.
|
||||
|
||||
|
||||
Args:
|
||||
input_ids: Входные токены
|
||||
past_key_values: Кешированные ключи и значения
|
||||
|
||||
|
||||
Returns:
|
||||
dict: Подготовленные входные данные
|
||||
"""
|
||||
# Наша простая реализация пока не поддерживает past_key_values
|
||||
return {"input_ids": input_ids}
|
||||
|
||||
|
||||
def can_generate(self) -> bool:
|
||||
"""Проверяет, может ли модель генерировать текст."""
|
||||
return True
|
||||
|
||||
|
||||
def generate(
|
||||
self,
|
||||
input_ids: Optional[torch.Tensor] = None,
|
||||
@@ -163,32 +162,32 @@ class HFGPTAdapter(PreTrainedModel):
|
||||
generation_config: Optional[GenerationConfig] = None,
|
||||
logits_processor: Optional[LogitsProcessorList] = None,
|
||||
stopping_criteria: Optional[StoppingCriteriaList] = None,
|
||||
**kwargs
|
||||
**kwargs,
|
||||
) -> torch.Tensor:
|
||||
"""
|
||||
Генерация текста с поддержкой HuggingFace интерфейса.
|
||||
|
||||
|
||||
Args:
|
||||
input_ids: Входные токены
|
||||
attention_mask: Маска внимания
|
||||
generation_config: Конфигурация генерации
|
||||
logits_processor: Процессоры логитов
|
||||
stopping_criteria: Критерии остановки
|
||||
|
||||
|
||||
Returns:
|
||||
torch.Tensor: Сгенерированные токены
|
||||
"""
|
||||
# Извлекаем обязательные параметры из kwargs или используем значения по умолчанию
|
||||
max_new_tokens = kwargs.pop('max_new_tokens', 50)
|
||||
do_sample = kwargs.pop('do_sample', True)
|
||||
|
||||
max_new_tokens = kwargs.pop("max_new_tokens", 50)
|
||||
do_sample = kwargs.pop("do_sample", True)
|
||||
|
||||
# Используем встроенную генерацию llm модели
|
||||
return self.llm_model.generate(
|
||||
x=input_ids,
|
||||
max_new_tokens=max_new_tokens,
|
||||
do_sample=do_sample,
|
||||
attention_mask=attention_mask,
|
||||
**kwargs
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
@@ -196,64 +195,66 @@ class HFAdapter:
|
||||
"""
|
||||
Основной класс адаптера для преобразования моделей llm в формат HuggingFace.
|
||||
"""
|
||||
|
||||
|
||||
@staticmethod
|
||||
def from_llm_model(
|
||||
llm_model: GPT,
|
||||
hf_config: Optional[HFAdapterConfig] = None
|
||||
llm_model: GPT, hf_config: Optional[HFAdapterConfig] = None
|
||||
) -> HFGPTAdapter:
|
||||
"""
|
||||
Создает адаптер из существующей llm модели.
|
||||
|
||||
|
||||
Args:
|
||||
llm_model: Обученная модель из библиотеки llm
|
||||
hf_config: Конфигурация для HuggingFace
|
||||
|
||||
|
||||
Returns:
|
||||
HFGPTAdapter: Адаптированная модель
|
||||
"""
|
||||
if hf_config is None:
|
||||
# Создаем конфигурацию из модели llm
|
||||
hf_config = HFAdapterConfig.from_llm_config(llm_model.config)
|
||||
|
||||
|
||||
# Преобразуем в PretrainedConfig
|
||||
pretrained_config = HFPretrainedConfig(**hf_config.to_dict())
|
||||
|
||||
|
||||
return HFGPTAdapter(pretrained_config, llm_model)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def from_pretrained(
|
||||
model_path: str,
|
||||
hf_config: Optional[HFAdapterConfig] = None
|
||||
model_path: str, hf_config: Optional[HFAdapterConfig] = None
|
||||
) -> HFGPTAdapter:
|
||||
"""
|
||||
Загружает модель из чекпоинта и создает адаптер.
|
||||
|
||||
|
||||
Args:
|
||||
model_path: Путь к сохраненной модели
|
||||
hf_config: Конфигурация для HuggingFace
|
||||
|
||||
|
||||
Returns:
|
||||
HFGPTAdapter: Адаптированная модель
|
||||
"""
|
||||
# Загружаем состояние модели
|
||||
state_dict = torch.load(model_path, map_location='cpu')
|
||||
|
||||
state_dict = torch.load(model_path, map_location="cpu")
|
||||
|
||||
# Определяем конфигурацию из состояния модели или используем переданную
|
||||
if hf_config is None:
|
||||
# Пытаемся определить конфигурацию из состояния модели
|
||||
# Это упрощенный подход - в реальности нужно сохранять конфигурацию отдельно
|
||||
vocab_size = state_dict.get('_token_embeddings._embedding.weight', torch.zeros(50257, 768)).shape[0]
|
||||
embed_dim = state_dict.get('_token_embeddings._embedding.weight', torch.zeros(50257, 768)).shape[1]
|
||||
|
||||
vocab_size = state_dict.get(
|
||||
"_token_embeddings._embedding.weight", torch.zeros(50257, 768)
|
||||
).shape[0]
|
||||
embed_dim = state_dict.get(
|
||||
"_token_embeddings._embedding.weight", torch.zeros(50257, 768)
|
||||
).shape[1]
|
||||
|
||||
hf_config = HFAdapterConfig(
|
||||
vocab_size=vocab_size,
|
||||
hidden_size=embed_dim,
|
||||
# Остальные параметры можно установить по умолчанию
|
||||
)
|
||||
|
||||
|
||||
pretrained_config = HFPretrainedConfig(**hf_config.to_dict())
|
||||
|
||||
|
||||
# Создаем модель llm и загружаем веса
|
||||
llm_config = {
|
||||
"vocab_size": hf_config.vocab_size,
|
||||
@@ -263,21 +264,17 @@ class HFAdapter:
|
||||
"max_position_embeddings": hf_config.max_position_embeddings,
|
||||
"dropout": hf_config.hidden_dropout_prob,
|
||||
}
|
||||
|
||||
|
||||
llm_model = GPT(llm_config)
|
||||
llm_model.load_state_dict(state_dict)
|
||||
|
||||
|
||||
return HFGPTAdapter(pretrained_config, llm_model)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def save_pretrained(
|
||||
model: HFGPTAdapter,
|
||||
save_directory: str,
|
||||
**kwargs
|
||||
):
|
||||
def save_pretrained(model: HFGPTAdapter, save_directory: str, **kwargs):
|
||||
"""
|
||||
Сохраняет адаптированную модель в формате HuggingFace.
|
||||
|
||||
|
||||
Args:
|
||||
model: Адаптированная модель
|
||||
save_directory: Директория для сохранения
|
||||
@@ -285,19 +282,19 @@ class HFAdapter:
|
||||
"""
|
||||
import os
|
||||
import json
|
||||
|
||||
|
||||
# Создаем директорию если не существует
|
||||
os.makedirs(save_directory, exist_ok=True)
|
||||
|
||||
|
||||
# Сохраняем конфигурацию
|
||||
config_path = os.path.join(save_directory, "config.json")
|
||||
with open(config_path, 'w', encoding='utf-8') as f:
|
||||
with open(config_path, "w", encoding="utf-8") as f:
|
||||
json.dump(model.config.to_dict(), f, indent=2, ensure_ascii=False)
|
||||
|
||||
|
||||
# Сохраняем веса модели
|
||||
model_path = os.path.join(save_directory, "pytorch_model.bin")
|
||||
torch.save(model.llm_model.state_dict(), model_path)
|
||||
|
||||
|
||||
# Сохраняем токенизатор если передан
|
||||
if hasattr(kwargs, 'tokenizer') and kwargs['tokenizer'] is not None:
|
||||
kwargs['tokenizer'].save_pretrained(save_directory)
|
||||
if hasattr(kwargs, "tokenizer") and kwargs["tokenizer"] is not None:
|
||||
kwargs["tokenizer"].save_pretrained(save_directory)
|
||||
|
||||
Reference in New Issue
Block a user