Рефакторинг: единообразие оформления кода (пробелы, кавычки, пустые строки), без изменения логики по всему проекту.

This commit is contained in:
Sergey Penkovsky
2025-10-06 22:57:19 +03:00
parent 332cad6159
commit 712278e33c
49 changed files with 2324 additions and 2004 deletions

View File

@@ -14,55 +14,57 @@ class HFUtils:
"""
Утилиты для работы с HuggingFace адаптером.
"""
@staticmethod
def create_hf_config_from_llm(llm_config: Dict[str, Any]) -> HFPretrainedConfig:
"""
Создает конфигурацию HuggingFace из конфигурации llm.
Args:
llm_config: Конфигурация модели из библиотеки llm
Returns:
HFPretrainedConfig: Конфигурация для HuggingFace
"""
adapter_config = HFAdapterConfig.from_llm_config(llm_config)
return HFPretrainedConfig(**adapter_config.to_dict())
@staticmethod
def convert_to_hf_format(
llm_model,
tokenizer = None,
model_name: str = "custom-gpt"
llm_model, tokenizer=None, model_name: str = "custom-gpt"
) -> tuple:
"""
Конвертирует llm модель в формат HuggingFace.
Args:
llm_model: Модель из библиотеки llm
tokenizer: Токенизатор (HF или кастомный)
model_name: Имя модели для сохранения
Returns:
tuple: (адаптированная модель, токенизатор)
"""
# Создаем адаптер
hf_model = HFAdapter.from_llm_model(llm_model)
# Если токенизатор не передан, создаем стандартный
if tokenizer is None:
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("gpt2")
# Устанавливаем специальные токены
if tokenizer.pad_token is None:
tokenizer.pad_token = tokenizer.eos_token
elif hasattr(tokenizer, '__class__') and 'BPETokenizer' in str(tokenizer.__class__):
elif hasattr(tokenizer, "__class__") and "BPETokenizer" in str(
tokenizer.__class__
):
# Если передан наш кастомный токенизатор, создаем адаптер
from .hf_tokenizer import create_hf_tokenizer
tokenizer = create_hf_tokenizer(tokenizer)
return hf_model, tokenizer
@staticmethod
def push_to_hub(
model: HFGPTAdapter,
@@ -70,11 +72,11 @@ class HFUtils:
repo_name: str,
organization: Optional[str] = None,
private: bool = False,
**kwargs
**kwargs,
):
"""
Загружает модель в HuggingFace Hub.
Args:
model: Адаптированная модель
tokenizer: Токенизатор
@@ -85,23 +87,23 @@ class HFUtils:
"""
try:
from huggingface_hub import HfApi, ModelCard, create_repo
# Создаем репозиторий
if organization:
repo_id = f"{organization}/{repo_name}"
else:
repo_id = repo_name
create_repo(repo_id, private=private, exist_ok=True)
# Сохраняем модель локально
import tempfile
import os
with tempfile.TemporaryDirectory() as tmp_dir:
# Сохраняем модель
HFAdapter.save_pretrained(model, tmp_dir, tokenizer=tokenizer)
# Создаем Model Card
card = ModelCard.from_template(
model_name=repo_name,
@@ -110,46 +112,43 @@ class HFUtils:
tags=["llm", "gpt", "custom"],
)
card.save(os.path.join(tmp_dir, "README.md"))
# Загружаем в Hub
api = HfApi()
api.upload_folder(
folder_path=tmp_dir,
repo_id=repo_id,
commit_message="Initial commit with custom GPT model"
commit_message="Initial commit with custom GPT model",
)
print(f"✅ Модель успешно загружена в HuggingFace Hub: {repo_id}")
except ImportError:
raise ImportError(
"Для загрузки в HuggingFace Hub установите huggingface_hub: "
"pip install huggingface_hub"
)
@staticmethod
def load_from_hub(
repo_id: str,
**kwargs
) -> tuple:
def load_from_hub(repo_id: str, **kwargs) -> tuple:
"""
Загружает модель из HuggingFace Hub.
Args:
repo_id: ID репозитория
**kwargs: Дополнительные параметры
Returns:
tuple: (модель, токенизатор)
"""
from transformers import AutoTokenizer
# Загружаем токенизатор
tokenizer = AutoTokenizer.from_pretrained(repo_id, **kwargs)
# Загружаем конфигурацию
config = AutoConfig.from_pretrained(repo_id, **kwargs)
# Создаем модель llm на основе конфигурации
llm_config = {
"vocab_size": config.vocab_size,
@@ -159,63 +158,56 @@ class HFUtils:
"max_position_embeddings": config.max_position_embeddings,
"dropout": config.hidden_dropout_prob,
}
# Загружаем модель через адаптер
model = HFAdapter.from_pretrained(
f"{repo_id}/pytorch_model.bin",
HFAdapterConfig.from_llm_config(llm_config)
f"{repo_id}/pytorch_model.bin", HFAdapterConfig.from_llm_config(llm_config)
)
return model, tokenizer
@staticmethod
def compare_with_hf_model(
llm_model,
hf_model_name: str = "gpt2",
test_input: str = "Hello world"
llm_model, hf_model_name: str = "gpt2", test_input: str = "Hello world"
) -> Dict[str, Any]:
"""
Сравнивает llm модель с эталонной моделью из HuggingFace.
Args:
llm_model: Модель из библиотеки llm
hf_model_name: Имя модели HuggingFace для сравнения
test_input: Тестовый вход
Returns:
Dict: Результаты сравнения
"""
from transformers import AutoModelForCausalLM, AutoTokenizer
# Загружаем эталонную модель
hf_tokenizer = AutoTokenizer.from_pretrained(hf_model_name)
hf_model = AutoModelForCausalLM.from_pretrained(hf_model_name)
# Подготавливаем входные данные
inputs = hf_tokenizer(test_input, return_tensors="pt")
# Получаем логиты от обеих моделей
with torch.no_grad():
hf_logits = hf_model(**inputs).logits
llm_logits = llm_model(inputs['input_ids'])
llm_logits = llm_model(inputs["input_ids"])
# Сравниваем результаты
hf_probs = torch.softmax(hf_logits[0, -1], dim=-1)
llm_probs = torch.softmax(llm_logits[0, -1], dim=-1)
# Вычисляем метрики
kl_divergence = torch.nn.functional.kl_div(
torch.log(llm_probs + 1e-8),
hf_probs,
reduction='batchmean'
torch.log(llm_probs + 1e-8), hf_probs, reduction="batchmean"
)
cosine_similarity = torch.nn.functional.cosine_similarity(
hf_logits.flatten(),
llm_logits.flatten(),
dim=0
hf_logits.flatten(), llm_logits.flatten(), dim=0
)
return {
"kl_divergence": kl_divergence.item(),
"cosine_similarity": cosine_similarity.item(),
@@ -228,58 +220,52 @@ class TokenizerWrapper:
"""
Обертка для токенизатора с дополнительными утилитами.
"""
def __init__(self, tokenizer):
self.tokenizer = tokenizer
def encode_batch(self, texts: List[str], **kwargs) -> Dict[str, torch.Tensor]:
"""
Кодирует батч текстов.
Args:
texts: Список текстов
**kwargs: Дополнительные параметры токенизации
Returns:
Dict: Токенизированные данные
"""
return self.tokenizer(
texts,
padding=True,
truncation=True,
return_tensors="pt",
**kwargs
texts, padding=True, truncation=True, return_tensors="pt", **kwargs
)
def decode_batch(self, token_ids: torch.Tensor, **kwargs) -> List[str]:
"""
Декодирует батч токенов.
Args:
token_ids: Тензор с токенами
**kwargs: Дополнительные параметры декодирования
Returns:
List[str]: Декодированные тексты
"""
if token_ids.dim() == 1:
token_ids = token_ids.unsqueeze(0)
texts = []
for i in range(token_ids.size(0)):
text = self.tokenizer.decode(
token_ids[i],
skip_special_tokens=True,
**kwargs
token_ids[i], skip_special_tokens=True, **kwargs
)
texts.append(text)
return texts
def get_vocab_size(self) -> int:
"""Возвращает размер словаря."""
return len(self.tokenizer)
def get_special_tokens(self) -> Dict[str, int]:
"""Возвращает специальные токены."""
return {
@@ -290,36 +276,27 @@ class TokenizerWrapper:
}
def create_hf_pipeline(
llm_model,
tokenizer=None,
device: str = "auto",
**kwargs
):
def create_hf_pipeline(llm_model, tokenizer=None, device: str = "auto", **kwargs):
"""
Создает HuggingFace pipeline из llm модели.
Args:
llm_model: Модель из библиотеки llm
tokenizer: Токенизатор
device: Устройство для вычислений
**kwargs: Дополнительные параметры pipeline
Returns:
transformers.Pipeline: Готовый pipeline
"""
from transformers import pipeline
# Конвертируем модель в HF формат
hf_model, tokenizer = HFUtils.convert_to_hf_format(llm_model, tokenizer)
# Создаем pipeline
pipe = pipeline(
"text-generation",
model=hf_model,
tokenizer=tokenizer,
device=device,
**kwargs
"text-generation", model=hf_model, tokenizer=tokenizer, device=device, **kwargs
)
return pipe