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

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,54 +14,50 @@ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from hf_proxy import HFAdapter, HFTokenizerAdapter, create_hf_pipeline
from shared.configs import (
TEST_PROMPTS, GENERATION_CONFIG, PATHS
)
from shared.data import (
print_experiment_info, ensure_directories, ExperimentLogger
)
from shared.configs import TEST_PROMPTS, GENERATION_CONFIG, PATHS
from shared.data import print_experiment_info, ensure_directories, ExperimentLogger
def load_hf_model_and_tokenizer() -> tuple:
"""
Загружает модель и токенизатор в формате HuggingFace.
Returns:
tuple: (hf_model, hf_tokenizer, model_config)
"""
# Используем упрощенную версию модели
model_path = "checkpoints/hf_simple_trained"
tokenizer_path = "checkpoints/hf_simple_tokenizer"
# Проверяем существование файлов
if not os.path.exists(model_path):
raise FileNotFoundError(
f"Модель не найдена: {model_path}\n"
f"Сначала обучите модель: uv run python experiments/hf_integration/simple_hf_training.py"
)
if not os.path.exists(tokenizer_path):
raise FileNotFoundError(
f"Токенизатор не найден: {tokenizer_path}"
)
raise FileNotFoundError(f"Токенизатор не найден: {tokenizer_path}")
# Загружаем адаптированный токенизатор
print("🔧 Загрузка адаптированного токенизатора...")
hf_tokenizer = HFTokenizerAdapter.from_pretrained(tokenizer_path)
print(f"✅ Токенизатор загружен (vocab_size={hf_tokenizer.vocab_size})")
# Загружаем конфигурацию модели
import json
config_path = os.path.join(model_path, "config.json")
with open(config_path, 'r', encoding='utf-8') as f:
with open(config_path, "r", encoding="utf-8") as f:
model_config = json.load(f)
# Загружаем модель через HFAdapter с правильной конфигурацией
print("🔧 Загрузка адаптированной модели...")
model_bin_path = os.path.join(model_path, "pytorch_model.bin")
# Создаем конфигурацию из сохраненного config.json
from hf_proxy import HFAdapterConfig
hf_config = HFAdapterConfig(
vocab_size=model_config["vocab_size"],
hidden_size=model_config["hidden_size"],
@@ -69,26 +65,28 @@ def load_hf_model_and_tokenizer() -> tuple:
num_attention_heads=model_config["num_attention_heads"],
max_position_embeddings=model_config["max_position_embeddings"],
hidden_dropout_prob=model_config.get("hidden_dropout_prob", 0.1),
attention_probs_dropout_prob=model_config.get("attention_probs_dropout_prob", 0.1),
attention_probs_dropout_prob=model_config.get(
"attention_probs_dropout_prob", 0.1
),
)
hf_model = HFAdapter.from_pretrained(model_bin_path, hf_config=hf_config)
hf_model.eval()
print("✅ Модель загружена")
return hf_model, hf_tokenizer, model_config
def test_hf_pipeline(hf_model, hf_tokenizer):
"""
Тестирует создание HuggingFace pipeline.
Args:
hf_model: Адаптированная модель
hf_tokenizer: Адаптированный токенизатор
"""
print("\n🧪 Тестирование HuggingFace pipeline...")
try:
# Создаем pipeline
pipe = create_hf_pipeline(
@@ -97,23 +95,23 @@ def test_hf_pipeline(hf_model, hf_tokenizer):
device="cpu",
max_length=50,
do_sample=True,
temperature=0.7
temperature=0.7,
)
print("✅ HuggingFace pipeline создан")
# Тестируем pipeline
test_prompts = TEST_PROMPTS[:3]
for prompt in test_prompts:
print(f"\n🔤 Промпт: '{prompt}'")
try:
result = pipe(prompt, max_new_tokens=20)
print(f"🎯 Результат: {result[0]['generated_text']}")
except Exception as e:
print(f"❌ Ошибка в pipeline: {e}")
except Exception as e:
print(f"❌ Ошибка создания pipeline: {e}")
@@ -121,47 +119,49 @@ def test_hf_pipeline(hf_model, hf_tokenizer):
def generate_with_hf_model(hf_model, hf_tokenizer, prompt: str, config: dict) -> str:
"""
Генерирует текст через адаптированную модель HF.
Args:
hf_model: Адаптированная модель
hf_tokenizer: Адаптированный токенизатор
prompt: Входной текст
config: Конфигурация генерации
Returns:
str: Сгенерированный текст
"""
print(f"🔤 Промпт: '{prompt}'")
print(f"📊 Параметры: max_tokens={config['max_new_tokens']}, "
f"temp={config['temperature']}, sample={config['do_sample']}")
print(
f"📊 Параметры: max_tokens={config['max_new_tokens']}, "
f"temp={config['temperature']}, sample={config['do_sample']}"
)
# Кодируем через адаптированный токенизатор
inputs = hf_tokenizer(prompt, return_tensors="pt")
print(f"🎯 Токены промпта: {inputs['input_ids'].tolist()[0]}")
print("🔄 Генерация через HF адаптер...")
# Генерируем через адаптированную модель
with torch.no_grad():
generated_ids = hf_model.generate(
input_ids=inputs['input_ids'],
input_ids=inputs["input_ids"],
max_new_tokens=config["max_new_tokens"],
do_sample=config["do_sample"],
temperature=config["temperature"],
top_k=config["top_k"],
top_p=config["top_p"]
top_p=config["top_p"],
)
# Декодируем через адаптированный токенизатор
generated_text = hf_tokenizer.decode(generated_ids[0], skip_special_tokens=True)
return generated_text
def test_different_hf_strategies(hf_model, hf_tokenizer, prompt: str):
"""
Тестирует разные стратегии генерации через HF интерфейс.
Args:
hf_model: Адаптированная модель
hf_tokenizer: Адаптированный токенизатор
@@ -169,32 +169,38 @@ def test_different_hf_strategies(hf_model, hf_tokenizer, prompt: str):
"""
print(f"\n🎭 Сравнение стратегий генерации через HF для промпта: '{prompt}'")
print("=" * 70)
strategies = [
{"name": "🎯 Жадный поиск", "do_sample": False, "temperature": 1.0},
{"name": "🎲 Вероятностная (temp=0.7)", "do_sample": True, "temperature": 0.7},
{"name": "🔥 Случайная (temp=1.2)", "do_sample": True, "temperature": 1.2},
{"name": "❄️ Детерминированная (temp=0.3)", "do_sample": True, "temperature": 0.3},
{
"name": "❄️ Детерминированная (temp=0.3)",
"do_sample": True,
"temperature": 0.3,
},
]
for strategy in strategies:
print(f"\n{strategy['name']}:")
try:
config = GENERATION_CONFIG.copy()
config.update({
"do_sample": strategy["do_sample"],
"temperature": strategy["temperature"],
"max_new_tokens": 20
})
config.update(
{
"do_sample": strategy["do_sample"],
"temperature": strategy["temperature"],
"max_new_tokens": 20,
}
)
generated = generate_with_hf_model(hf_model, hf_tokenizer, prompt, config)
# Выделяем сгенерированную часть
generated_part = generated[len(prompt):]
generated_part = generated[len(prompt) :]
print(f" 📤 Промпт: '{prompt}'")
print(f" 🎯 Сгенерировано: '{generated_part}'")
print(f" 📄 Полный текст: '{generated}'")
except Exception as e:
print(f" ❌ Ошибка: {e}")
@@ -202,30 +208,30 @@ def test_different_hf_strategies(hf_model, hf_tokenizer, prompt: str):
def analyze_hf_tokenization(hf_tokenizer, texts: list):
"""
Анализирует токенизацию через адаптированный токенизатор.
Args:
hf_tokenizer: Адаптированный токенизатор
texts: Список текстов для анализа
"""
print(f"\n🔍 Анализ токенизации через HF адаптер:")
print("=" * 60)
for i, text in enumerate(texts):
print(f"\nТекст {i+1}: '{text}'")
# Токенизация через адаптер
inputs = hf_tokenizer(text, return_tensors="pt")
tokens = inputs['input_ids'].tolist()[0]
tokens = inputs["input_ids"].tolist()[0]
token_strings = hf_tokenizer.tokenize(text)
print(f" Токены (ID): {tokens}")
print(f" Токены (текст): {token_strings}")
print(f" Количество токенов: {len(tokens)}")
# Декодирование обратно
decoded = hf_tokenizer.decode(tokens)
print(f" Декодированный: '{decoded}'")
if text == decoded:
print(f" ✅ Декодирование корректно")
else:
@@ -235,51 +241,55 @@ def analyze_hf_tokenization(hf_tokenizer, texts: list):
def interactive_hf_generation(hf_model, hf_tokenizer):
"""
Режим интерактивной генерации через HF интерфейс.
Args:
hf_model: Адаптированная модель
hf_tokenizer: Адаптированный токенизатор
"""
print(f"\n💬 Интерактивная генерация через HF (для выхода введите 'exit')")
print("-" * 60)
while True:
try:
user_input = input("\n🔤 Введите промпт: ").strip()
if user_input.lower() in ['exit', 'quit', 'выход']:
if user_input.lower() in ["exit", "quit", "выход"]:
break
if not user_input:
continue
# Запрашиваем параметры
try:
max_tokens = int(input("📏 Макс. токенов [50]: ") or "50")
temperature = float(input("🌡️ Температура [0.7]: ") or "0.7")
do_sample_input = input("🎲 Сэмплирование (y/n) [y]: ").lower()
do_sample = do_sample_input != 'n'
do_sample = do_sample_input != "n"
except:
max_tokens = 50
temperature = 0.7
do_sample = True
print("⚠️ Использую параметры по умолчанию")
config = GENERATION_CONFIG.copy()
config.update({
"max_new_tokens": max_tokens,
"temperature": temperature,
"do_sample": do_sample
})
generated = generate_with_hf_model(hf_model, hf_tokenizer, user_input, config)
generated_part = generated[len(user_input):]
config.update(
{
"max_new_tokens": max_tokens,
"temperature": temperature,
"do_sample": do_sample,
}
)
generated = generate_with_hf_model(
hf_model, hf_tokenizer, user_input, config
)
generated_part = generated[len(user_input) :]
print(f"\n🎯 Результат:")
print(f" 📤 Промпт: '{user_input}'")
print(f" 🎯 Сгенерировано: '{generated_part}'")
print(f" 📄 Полный текст: '{generated}'")
except KeyboardInterrupt:
print("\n👋 Завершение работы...")
break
@@ -295,76 +305,79 @@ def main():
"model": "GPT через HFAdapter",
"tokenizer": "BPE через HFTokenizerAdapter",
"инструменты": "HuggingFace pipeline & генерация",
"стратегия": "интеграция с HF экосистемой"
"стратегия": "интеграция с HF экосистемой",
}
print_experiment_info(experiment_name, experiment_config)
ensure_directories()
logger = ExperimentLogger(experiment_name)
try:
# Загружаем модель и токенизатор в HF формате
hf_model, hf_tokenizer, model_config = load_hf_model_and_tokenizer()
# === Анализ токенизации ===
analysis_texts = [
"Искусственный интеллект",
"Нейронные сети",
"Машинное обучение"
"Нейронные сети",
"Машинное обучение",
]
analyze_hf_tokenization(hf_tokenizer, analysis_texts)
# === Тестирование HF pipeline ===
test_hf_pipeline(hf_model, hf_tokenizer)
# === Генерация с разными промптами ===
print(f"\n🎯 Генерация текста через HF адаптер")
print("=" * 60)
for i, prompt in enumerate(TEST_PROMPTS):
print(f"\n📝 Пример {i+1}/{len(TEST_PROMPTS)}")
print("-" * 40)
try:
generated = generate_with_hf_model(hf_model, hf_tokenizer, prompt, GENERATION_CONFIG)
generated = generate_with_hf_model(
hf_model, hf_tokenizer, prompt, GENERATION_CONFIG
)
# Выделяем сгенерированную часть
generated_part = generated[len(prompt):]
generated_part = generated[len(prompt) :]
print(f"📤 Промпт: '{prompt}'")
print(f"🎯 Сгенерировано: '{generated_part}'")
print(f"📄 Полный текст: '{generated}'")
print(f"📏 Длина: {len(generated)} символов")
# Логируем успешную генерацию
logger.log_metric(f"hf_generation_length_{i}", len(generated))
except Exception as e:
print(f"❌ Ошибка при генерации: {e}")
continue
# === Сравнение стратегий генерации ===
test_prompt = "Искусственный"
test_different_hf_strategies(hf_model, hf_tokenizer, test_prompt)
# === Интерактивная генерация ===
interactive_hf_generation(hf_model, hf_tokenizer)
# === Сохранение результатов ===
logger.save_logs("checkpoints/hf_integration_generation_logs.json")
print(f"\n🎉 Эксперимент с HF интеграцией завершен успешно!")
print(f"\n📚 Достигнутая интеграция:")
print(f" ✅ Загрузка модели и токенизатора в HF формате")
print(f" ✅ Использование HF pipeline")
print(f" ✅ Генерация через стандартные HF интерфейсы")
print(f" ✅ Совместимость с HF экосистемой")
except FileNotFoundError as e:
print(f"{e}")
except Exception as e:
print(f"❌ Ошибка в эксперименте: {e}")
import traceback
traceback.print_exc()

View File

@@ -19,141 +19,139 @@ from llm.tokenizers import BPETokenizer
from hf_proxy import HFAdapter, HFTokenizerAdapter
from shared.configs import (
TRAIN_TEXTS, BASE_GPT_CONFIG, BPE_CONFIG,
TRAINING_CONFIG, PATHS, TEST_PROMPTS
TRAIN_TEXTS,
BASE_GPT_CONFIG,
BPE_CONFIG,
TRAINING_CONFIG,
PATHS,
TEST_PROMPTS,
)
def create_dataset(hf_tokenizer, texts, max_length=128):
"""
Создает простой датасет для обучения.
Args:
hf_tokenizer: Адаптированный токенизатор
texts: Список текстов
max_length: Максимальная длина последовательности
Returns:
list: Список тензоров input_ids
"""
dataset = []
for text in texts:
# Токенизируем текст
inputs = hf_tokenizer(
text,
max_length=max_length,
text,
max_length=max_length,
truncation=True,
padding=False,
return_tensors="pt"
return_tensors="pt",
)
input_ids = inputs['input_ids'][0]
input_ids = inputs["input_ids"][0]
# Создаем метки для языкового моделирования
labels = input_ids.clone()
dataset.append({
'input_ids': input_ids,
'labels': labels
})
dataset.append({"input_ids": input_ids, "labels": labels})
return dataset
def manual_training_loop(hf_model, hf_tokenizer, train_texts, val_texts, config):
"""
Ручной цикл обучения без использования Trainer.
Args:
hf_model: Адаптированная модель
hf_tokenizer: Адаптированный токенизатор
train_texts: Тексты для обучения
val_texts: Тексты для валидации
config: Конфигурация обучения
Returns:
dict: Результаты обучения
"""
print("🎯 Запуск ручного обучения...")
# Создаем датасеты
train_dataset = create_dataset(hf_tokenizer, train_texts)
val_dataset = create_dataset(hf_tokenizer, val_texts)
print(f"📊 Данные: {len(train_dataset)} train, {len(val_dataset)} validation")
# Оптимизатор
optimizer = torch.optim.AdamW(
hf_model.parameters(),
lr=config["learning_rate"]
)
optimizer = torch.optim.AdamW(hf_model.parameters(), lr=config["learning_rate"])
# Функция потерь
loss_fn = nn.CrossEntropyLoss()
# Обучение
hf_model.train()
train_losses = []
val_losses = []
for epoch in range(config["num_epochs"]):
print(f"\n📅 Эпоха {epoch + 1}/{config['num_epochs']}")
# Обучение
epoch_train_loss = 0
for i, batch in enumerate(train_dataset):
optimizer.zero_grad()
input_ids = batch['input_ids'].unsqueeze(0) # [1, seq_len]
labels = batch['labels'].unsqueeze(0) # [1, seq_len]
input_ids = batch["input_ids"].unsqueeze(0) # [1, seq_len]
labels = batch["labels"].unsqueeze(0) # [1, seq_len]
# Forward pass
outputs = hf_model(input_ids=input_ids, labels=labels)
loss = outputs.loss
# Backward pass
loss.backward()
optimizer.step()
epoch_train_loss += loss.item()
if i % 5 == 0:
print(f" Batch {i}/{len(train_dataset)}: loss = {loss.item():.4f}")
avg_train_loss = epoch_train_loss / len(train_dataset)
train_losses.append(avg_train_loss)
print(f" 📊 Средняя train loss: {avg_train_loss:.4f}")
# Валидация
hf_model.eval()
epoch_val_loss = 0
with torch.no_grad():
for batch in val_dataset:
input_ids = batch['input_ids'].unsqueeze(0)
labels = batch['labels'].unsqueeze(0)
input_ids = batch["input_ids"].unsqueeze(0)
labels = batch["labels"].unsqueeze(0)
outputs = hf_model(input_ids=input_ids, labels=labels)
epoch_val_loss += outputs.loss.item()
avg_val_loss = epoch_val_loss / len(val_dataset)
val_losses.append(avg_val_loss)
print(f" 📊 Средняя val loss: {avg_val_loss:.4f}")
hf_model.train()
return {
'train_losses': train_losses,
'val_losses': val_losses,
'final_train_loss': train_losses[-1],
'final_val_loss': val_losses[-1]
"train_losses": train_losses,
"val_losses": val_losses,
"final_train_loss": train_losses[-1],
"final_val_loss": val_losses[-1],
}
def test_generation_after_training(hf_model, hf_tokenizer, test_prompts):
"""
Тестирует генерацию после обучения.
Args:
hf_model: Обученная модель
hf_tokenizer: Токенизатор
@@ -161,24 +159,24 @@ def test_generation_after_training(hf_model, hf_tokenizer, test_prompts):
"""
print("\n🧪 Тестирование генерации после обучения...")
hf_model.eval()
for prompt in test_prompts[:3]:
print(f"\n🔤 Промпт: '{prompt}'")
try:
inputs = hf_tokenizer(prompt, return_tensors="pt")
with torch.no_grad():
generated = hf_model.generate(
input_ids=inputs['input_ids'],
input_ids=inputs["input_ids"],
max_new_tokens=20,
do_sample=True,
temperature=0.8
temperature=0.8,
)
generated_text = hf_tokenizer.decode(generated[0], skip_special_tokens=True)
print(f"🎯 Результат: '{generated_text}'")
except Exception as e:
print(f"❌ Ошибка генерации: {e}")
@@ -188,96 +186,102 @@ def main():
print("=" * 60)
print("🚀 УПРОЩЕННОЕ ОБУЧЕНИЕ GPT С HF-PROXY")
print("=" * 60)
try:
# === Подготовка данных ===
print("🔧 Подготовка данных...")
train_texts = TRAIN_TEXTS[:10] # Используем меньше данных для быстрого тестирования
train_texts = TRAIN_TEXTS[
:10
] # Используем меньше данных для быстрого тестирования
val_texts = TRAIN_TEXTS[10:12]
print(f"📊 Данные: {len(train_texts)} train, {len(val_texts)} validation")
# === Подготовка токенизатора ===
print("🔧 Подготовка токенизатора...")
llm_tokenizer = BPETokenizer()
llm_tokenizer.train(
texts=train_texts,
vocab_size=BPE_CONFIG["vocab_size"],
special_tokens=BPE_CONFIG["special_tokens"]
special_tokens=BPE_CONFIG["special_tokens"],
)
hf_tokenizer = HFTokenizerAdapter(llm_tokenizer)
print(f"✅ Токенизатор создан (vocab_size={hf_tokenizer.vocab_size})")
# === Подготовка модели ===
print("🔧 Подготовка модели...")
model_config = BASE_GPT_CONFIG.copy()
model_config["vocab_size"] = hf_tokenizer.vocab_size
llm_model = GPT(model_config)
hf_model = HFAdapter.from_llm_model(llm_model)
print(f"✅ Модель создана")
# === Тестирование до обучения ===
print("\n🧪 Тестирование до обучения...")
test_generation_after_training(hf_model, hf_tokenizer, TEST_PROMPTS)
# === Обучение ===
print(f"\n🎯 Обучение модели...")
training_config = {
"learning_rate": TRAINING_CONFIG["learning_rate"],
"num_epochs": 2, # Меньше эпох для быстрого тестирования
"batch_size": TRAINING_CONFIG["batch_size"]
"batch_size": TRAINING_CONFIG["batch_size"],
}
results = manual_training_loop(
hf_model, hf_tokenizer, train_texts, val_texts, training_config
)
print(f"\n📊 Результаты обучения:")
print(f" Final train loss: {results['final_train_loss']:.4f}")
print(f" Final val loss: {results['final_val_loss']:.4f}")
# === Тестирование после обучения ===
print("\n🧪 Тестирование после обучения...")
test_generation_after_training(hf_model, hf_tokenizer, TEST_PROMPTS)
# === Сохранение модели ===
print(f"\n💾 Сохранение модели...")
# Создаем директории
os.makedirs("checkpoints/hf_simple_trained", exist_ok=True)
os.makedirs("checkpoints/hf_simple_tokenizer", exist_ok=True)
# Сохраняем токенизатор
hf_tokenizer.save_pretrained("checkpoints/hf_simple_tokenizer")
print("✅ Токенизатор сохранен")
# Сохраняем модель
HFAdapter.save_pretrained(
hf_model,
"checkpoints/hf_simple_trained",
tokenizer=hf_tokenizer
hf_model, "checkpoints/hf_simple_trained", tokenizer=hf_tokenizer
)
print("✅ Модель сохранена")
# Сохраняем результаты
results_path = "checkpoints/simple_training_results.json"
with open(results_path, 'w', encoding='utf-8') as f:
json.dump({
'training_config': training_config,
'model_config': model_config,
'results': results
}, f, indent=2, ensure_ascii=False)
with open(results_path, "w", encoding="utf-8") as f:
json.dump(
{
"training_config": training_config,
"model_config": model_config,
"results": results,
},
f,
indent=2,
ensure_ascii=False,
)
print(f"✅ Результаты сохранены в {results_path}")
print(f"\n🎉 Упрощенное обучение завершено успешно!")
print(f"\n💡 Для использования обученной модели:")
print(f" uv run python experiments/hf_integration/generate_with_hf_tools.py")
except Exception as e:
print(f"❌ Ошибка в эксперименте: {e}")
import traceback
traceback.print_exc()

View File

@@ -16,158 +16,163 @@ from llm.tokenizers import BPETokenizer
from hf_proxy import HFAdapter, HFTokenizerAdapter
from shared.configs import (
TRAIN_TEXTS, BASE_GPT_CONFIG, BPE_CONFIG,
TEST_PROMPTS, GENERATION_CONFIG
TRAIN_TEXTS,
BASE_GPT_CONFIG,
BPE_CONFIG,
TEST_PROMPTS,
GENERATION_CONFIG,
)
def test_basic_hf_integration():
"""Тестирует базовую интеграцию hf-proxy."""
print("🧪 Тестирование базовой интеграции hf-proxy...")
# === Подготовка токенизатора ===
print("1. Подготовка токенизатора...")
llm_tokenizer = BPETokenizer()
llm_tokenizer.train(
texts=TRAIN_TEXTS,
vocab_size=BPE_CONFIG["vocab_size"],
special_tokens=BPE_CONFIG["special_tokens"]
special_tokens=BPE_CONFIG["special_tokens"],
)
hf_tokenizer = HFTokenizerAdapter(llm_tokenizer)
print(f" ✅ Токенизатор создан (vocab_size={hf_tokenizer.vocab_size})")
# === Подготовка модели ===
print("2. Подготовка модели...")
model_config = BASE_GPT_CONFIG.copy()
model_config["vocab_size"] = hf_tokenizer.vocab_size
llm_model = GPT(model_config)
hf_model = HFAdapter.from_llm_model(llm_model)
print(f" ✅ Модель создана")
# === Тестирование токенизации ===
print("3. Тестирование токенизации...")
test_texts = ["Искусственный интеллект", "Нейронные сети"]
for text in test_texts:
print(f" 📝 Текст: '{text}'")
# Оригинальный токенизатор
original_tokens = llm_tokenizer.encode(text)
print(f" Оригинальный: {len(original_tokens)} токенов")
# HF адаптер
hf_inputs = hf_tokenizer(text, return_tensors="pt")
print(f" HF адаптер: {hf_inputs['input_ids'].shape}")
# Декодирование
decoded = hf_tokenizer.decode(hf_inputs['input_ids'][0])
decoded = hf_tokenizer.decode(hf_inputs["input_ids"][0])
print(f" Декодированный: '{decoded}'")
# === Тестирование forward pass ===
print("4. Тестирование forward pass...")
for text in test_texts:
hf_inputs = hf_tokenizer(text, return_tensors="pt")
with torch.no_grad():
outputs = hf_model(**hf_inputs)
print(f" 📝 '{text}' -> logits: {outputs.logits.shape}")
# === Тестирование генерации ===
print("5. Тестирование генерации...")
hf_model.eval()
for prompt in TEST_PROMPTS[:3]:
print(f" 🔤 Промпт: '{prompt}'")
try:
inputs = hf_tokenizer(prompt, return_tensors="pt")
with torch.no_grad():
generated = hf_model.generate(
input_ids=inputs['input_ids'],
input_ids=inputs["input_ids"],
max_new_tokens=10,
do_sample=True,
temperature=0.8
temperature=0.8,
)
generated_text = hf_tokenizer.decode(generated[0], skip_special_tokens=True)
print(f" 🎯 Результат: '{generated_text}'")
except Exception as e:
print(f" ❌ Ошибка: {e}")
# === Тестирование сохранения/загрузки ===
print("6. Тестирование сохранения/загрузки...")
try:
# Сохраняем токенизатор
hf_tokenizer.save_pretrained("test_save/tokenizer")
print(" ✅ Токенизатор сохранен")
# Сохраняем модель
HFAdapter.save_pretrained(hf_model, "test_save/model", tokenizer=hf_tokenizer)
print(" ✅ Модель сохранена")
# Загружаем токенизатор
loaded_tokenizer = HFTokenizerAdapter.from_pretrained("test_save/tokenizer")
print(f" ✅ Токенизатор загружен (vocab_size={loaded_tokenizer.vocab_size})")
# Загружаем модель
model_path = os.path.join("test_save/model", "pytorch_model.bin")
loaded_model = HFAdapter.from_pretrained(model_path)
print(" ✅ Модель загружена")
# Проверяем работоспособность загруженной модели
test_input = hf_tokenizer("Тест", return_tensors="pt")
with torch.no_grad():
loaded_outputs = loaded_model(**test_input)
print(f" ✅ Загруженная модель работает (logits: {loaded_outputs.logits.shape})")
print(
f" ✅ Загруженная модель работает (logits: {loaded_outputs.logits.shape})"
)
except Exception as e:
print(f" ❌ Ошибка сохранения/загрузки: {e}")
print("\n🎉 Базовое тестирование hf-proxy завершено!")
def test_hf_tokenizer_methods():
"""Тестирует различные методы HF токенизатора."""
print("\n🧪 Тестирование методов HF токенизатора...")
# Создаем токенизатор
llm_tokenizer = BPETokenizer()
llm_tokenizer.train(
texts=TRAIN_TEXTS[:5],
vocab_size=500,
special_tokens=BPE_CONFIG["special_tokens"]
special_tokens=BPE_CONFIG["special_tokens"],
)
hf_tokenizer = HFTokenizerAdapter(llm_tokenizer)
test_text = "Искусственный интеллект и машинное обучение"
# Тестируем разные методы
print("1. Метод __call__:")
result = hf_tokenizer(test_text, return_tensors="pt")
print(f" Результат: {result}")
print("2. Метод encode:")
encoded = hf_tokenizer.encode(test_text)
print(f" Закодировано: {encoded}")
print("3. Метод decode:")
decoded = hf_tokenizer.decode(encoded)
print(f" Декодировано: '{decoded}'")
print("4. Метод tokenize:")
tokens = hf_tokenizer.tokenize(test_text)
print(f" Токены: {tokens}")
print("5. Метод get_vocab:")
vocab = hf_tokenizer.get_vocab()
print(f" Размер словаря: {len(vocab)}")
print("Все методы токенизатора работают!")
@@ -176,14 +181,14 @@ def main():
print("=" * 60)
print("🧪 ТЕСТИРОВАНИЕ HF-PROXY")
print("=" * 60)
try:
# Тестируем базовую интеграцию
test_basic_hf_integration()
# Тестируем методы токенизатора
test_hf_tokenizer_methods()
print("\n" + "=" * 60)
print("🎉 ВСЕ ТЕСТЫ ПРОЙДЕНЫ УСПЕШНО!")
print("=" * 60)
@@ -195,10 +200,11 @@ def main():
print(" ✅ Генерация текста")
print(" ✅ Сохранение и загрузка моделей")
print("Все методы HF токенизатора")
except Exception as e:
print(f"\n❌ Ошибка в тестировании: {e}")
import traceback
traceback.print_exc()

View File

@@ -17,28 +17,34 @@ from llm.tokenizers import BPETokenizer
from hf_proxy import HFAdapter, HFTokenizerAdapter
from shared.configs import (
TRAIN_TEXTS, BASE_GPT_CONFIG, BPE_CONFIG,
TRAINING_CONFIG, PATHS, TEST_PROMPTS
TRAIN_TEXTS,
BASE_GPT_CONFIG,
BPE_CONFIG,
TRAINING_CONFIG,
PATHS,
TEST_PROMPTS,
)
from shared.data import (
load_training_data, ensure_directories,
print_experiment_info, ExperimentLogger
load_training_data,
ensure_directories,
print_experiment_info,
ExperimentLogger,
)
def setup_hf_training():
"""
Настраивает окружение для обучения через HuggingFace Trainer.
Returns:
tuple: (hf_model, hf_tokenizer, llm_tokenizer, model_config)
"""
print("🔧 Настройка HuggingFace обучения...")
# === Подготовка данных ===
train_texts, val_texts = load_training_data()
print(f"📊 Данные: {len(train_texts)} train, {len(val_texts)} validation")
# === Обучение/загрузка токенизатора ===
if os.path.exists(PATHS["bpe_tokenizer"]):
print("📝 Загрузка BPE токенизатора...")
@@ -50,55 +56,55 @@ def setup_hf_training():
llm_tokenizer.train(
texts=TRAIN_TEXTS,
vocab_size=BPE_CONFIG["vocab_size"],
special_tokens=BPE_CONFIG["special_tokens"]
special_tokens=BPE_CONFIG["special_tokens"],
)
llm_tokenizer.save(PATHS["bpe_tokenizer"])
print(f"✅ Токенизатор обучен и сохранен")
# === Создание адаптера токенизатора ===
print("🔧 Создание адаптера HuggingFace для токенизатора...")
hf_tokenizer = HFTokenizerAdapter(llm_tokenizer)
print(f"✅ Адаптер токенизатора создан")
# === Инициализация модели ===
model_config = BASE_GPT_CONFIG.copy()
model_config["vocab_size"] = llm_tokenizer.get_vocab_size()
print("🔧 Создание GPT модели...")
llm_model = GPT(model_config)
# === Создание адаптера модели ===
print("🔧 Создание адаптера HuggingFace для модели...")
hf_model = HFAdapter.from_llm_model(llm_model)
print(f"✅ Адаптер модели создан")
return hf_model, hf_tokenizer, llm_tokenizer, model_config, train_texts, val_texts
def test_hf_integration(hf_model, hf_tokenizer, llm_tokenizer):
"""
Тестирует интеграцию с HuggingFace инструментами.
Args:
hf_model: Адаптированная модель
hf_tokenizer: Адаптированный токенизатор
llm_tokenizer: Оригинальный токенизатор
"""
print("\n🧪 Тестирование интеграции с HuggingFace...")
test_texts = ["Искусственный интеллект", "Нейронные сети"]
for text in test_texts:
print(f"\n🔤 Текст: '{text}'")
# Тестируем адаптированный токенизатор
hf_inputs = hf_tokenizer(text, return_tensors="pt")
print(f" HF токенизатор: {hf_inputs['input_ids'].shape}")
# Тестируем оригинальный токенизатор для сравнения
original_tokens = llm_tokenizer.encode(text)
print(f" Оригинальный токенизатор: {len(original_tokens)} токенов")
# Тестируем forward pass через адаптированную модель
try:
with torch.no_grad():
@@ -114,28 +120,35 @@ def main():
experiment_name = "Обучение GPT через HF Trainer (с hf-proxy)"
experiment_config = {
"model": "GPT через HFAdapter",
"tokenizer": "BPE через HFTokenizerAdapter",
"tokenizer": "BPE через HFTokenizerAdapter",
"trainer": "HuggingFace Trainer",
"vocab_size": BPE_CONFIG["vocab_size"],
"training_epochs": TRAINING_CONFIG["num_epochs"]
"training_epochs": TRAINING_CONFIG["num_epochs"],
}
print_experiment_info(experiment_name, experiment_config)
ensure_directories()
logger = ExperimentLogger(experiment_name)
try:
# Настраиваем обучение
hf_model, hf_tokenizer, llm_tokenizer, model_config, train_texts, val_texts = setup_hf_training()
(
hf_model,
hf_tokenizer,
llm_tokenizer,
model_config,
train_texts,
val_texts,
) = setup_hf_training()
# Тестируем интеграцию
test_hf_integration(hf_model, hf_tokenizer, llm_tokenizer)
# === Подготовка датасетов HuggingFace ===
print(f"\n📊 Подготовка датасетов HuggingFace...")
from datasets import Dataset
def tokenize_function(examples):
"""Функция токенизации для HF datasets."""
# Используем адаптированный токенизатор
@@ -147,11 +160,11 @@ def main():
)
tokenized["labels"] = tokenized["input_ids"].copy()
return tokenized
# Создаем датасеты
train_dataset = Dataset.from_dict({"text": train_texts})
val_dataset = Dataset.from_dict({"text": val_texts})
# Токенизируем
train_dataset = train_dataset.map(
tokenize_function,
@@ -163,26 +176,26 @@ def main():
batched=True,
remove_columns=val_dataset.column_names,
)
print(f" Train датасет: {len(train_dataset)} примеров")
print(f" Validation датасет: {len(val_dataset)} примеров")
# === Настройка HuggingFace Trainer ===
print(f"\n🔧 Настройка HuggingFace Trainer...")
from transformers import (
Trainer,
Trainer,
TrainingArguments,
DataCollatorForLanguageModeling
DataCollatorForLanguageModeling,
)
# Data collator для языкового моделирования
data_collator = DataCollatorForLanguageModeling(
tokenizer=hf_tokenizer,
mlm=False,
pad_to_multiple_of=8,
)
# Аргументы обучения
training_args = TrainingArguments(
output_dir=PATHS["hf_model"],
@@ -204,7 +217,7 @@ def main():
dataloader_pin_memory=False,
report_to=None,
)
# Создаем Trainer
trainer = Trainer(
model=hf_model,
@@ -213,84 +226,87 @@ def main():
eval_dataset=val_dataset,
data_collator=data_collator,
)
print("✅ HuggingFace Trainer настроен")
# === Запуск обучения ===
print(f"\n🎯 Запуск обучения через HuggingFace Trainer...")
train_result = trainer.train()
# Сохраняем лучшую модель
trainer.save_model()
hf_tokenizer.save_pretrained(PATHS["hf_model"])
print("✅ Обучение завершено успешно!")
print(f"📊 Final train loss: {train_result.metrics['train_loss']:.4f}")
if "eval_loss" in train_result.metrics:
print(f"📊 Final eval loss: {train_result.metrics['eval_loss']:.4f}")
# === Сохранение через hf-proxy ===
print(f"\n💾 Сохранение через hf-proxy...")
from hf_proxy import convert_to_hf_format
# Сохраняем токенизатор в HF формате
hf_tokenizer_dir = PATHS["hf_tokenizer"]
hf_tokenizer.save_pretrained(hf_tokenizer_dir)
# Сохраняем модель через hf-proxy
hf_proxy_dir = PATHS["hf_proxy_model"]
HFAdapter.save_pretrained(hf_model, hf_proxy_dir, tokenizer=hf_tokenizer)
print(f"✅ Модель сохранена в HF формате:")
print(f" - {PATHS['hf_model']}: стандартный HF формат")
print(f" - {hf_proxy_dir}: через hf-proxy")
print(f" - {hf_tokenizer_dir}: токенизатор в HF формате")
# === Тестирование генерации ===
print(f"\n🧪 Тестирование генерации после обучения...")
hf_model.eval()
for prompt in TEST_PROMPTS[:3]:
print(f"\n🔤 Промпт: '{prompt}'")
try:
inputs = hf_tokenizer(prompt, return_tensors="pt")
with torch.no_grad():
generated = hf_model.generate(
input_ids=inputs['input_ids'],
input_ids=inputs["input_ids"],
max_new_tokens=20,
do_sample=True,
temperature=0.8
temperature=0.8,
)
generated_text = hf_tokenizer.decode(generated[0], skip_special_tokens=True)
generated_text = hf_tokenizer.decode(
generated[0], skip_special_tokens=True
)
print(f"🎯 Результат: '{generated_text}'")
except Exception as e:
print(f"❌ Ошибка генерации: {e}")
# === Сохранение результатов ===
results = {
"experiment": experiment_name,
"model_config": model_config,
"training_config": TRAINING_CONFIG,
"final_loss": train_result.metrics.get('train_loss', 'N/A'),
"eval_loss": train_result.metrics.get('eval_loss', 'N/A')
"final_loss": train_result.metrics.get("train_loss", "N/A"),
"eval_loss": train_result.metrics.get("eval_loss", "N/A"),
}
logger.save_logs("checkpoints/hf_integration_training_logs.json")
print(f"\n🎉 Эксперимент с HF интеграцией завершен успешно!")
print(f"\n💡 Для использования обученной модели:")
print(f" uv run python experiments/hf_integration/generate_with_hf_tools.py")
except Exception as e:
print(f"❌ Ошибка в эксперименте: {e}")
import traceback
traceback.print_exc()