Повторите эксперимент GPT-1900: обучение модели на исторических текстах | AiManual
AiManual Logo Ai / Manual.
06 Апр 2026 Гайд

GPT-1900: Как заставить нейросеть говорить языком прошлого века на вашей видеокарте

Пошаговый гайд по обучению локальной LLM на исторических текстах. Сбор датасета, выбор модели, тонкая настройка и запуск инференса на своем железе.

Зачем учить нейросеть говорить как житель 1900 года?

Все началось с простого вопроса: что, если вместо того, чтобы спрашивать у универсальной модели о прошлом, создать модель, которая мыслит в прошлом? Не просто выдает факты, а рассуждает категориями эпохи, использует ее лексикон и не знает о событиях, которые еще не произошли. Эксперимент GPT-1900 – это не про создание очередного чат-бота. Это машина времени для лингвистов и историков, собранная на коленке.

Представь: ты спрашиваешь у стандартной LLM о транспорте в 1900 году. Она ответит про лошадей, первые автомобили, возможно, упомянет дирижабли. Скучно и безлико. А теперь спроси ту же вещь у модели, обученной только на газетах, письмах и технической литературе 1895-1905 годов. Она расскажет тебе о "безлошадных экипажах" с подробностями механических поломок, о стоимости содержания пары лошадей в городе, о панике из-за новых правил уличного движения. Разница – между сухим пересказом учебника и живым свидетельством.

Главная ошибка на старте – пытаться сделать модель "политкорректной". Если в твоих данных 1900 года встречаются термины и взгляды, которые сегодня считаются неприемлемыми, модель должна их отражать. Иначе ты создаешь не исследовательский инструмент, а цензурированную пародию. Мы строим не этического собеседника, а лингвистический артефакт.

От концепции к железу: что такое GPT-1900 на практике

Эксперимент GPT-1900 – это практическая демонстрация, что для глубокого погружения в узкую предметную область не нужны модели на 70 миллиардов параметров. Достаточно скромной архитектуры, правильно подготовленных данных и терпения. Мы не обучаем с нуля (хотя это возможно, как в случае с TimeCapsuleLLM), а делаем тонкую настройку (fine-tuning) уже существующей компактной модели.

Почему fine-tuning, а не обучение с нуля? Скорость и доступность. Обучение 2-миллиардной модели с нуля требует недель на кластере GPU. Fine-tuning той же модели на узком датасете можно выполнить за несколько часов на одной видеокарте потребительского уровня. А результат для нашей задачи будет сопоставим.

1 Собираем датасет: где найти голоса из прошлого

Качество данных решает все. Тебе нужны не отобранные историками тексты, а сырая повседневность. Забудь про Project Gutenberg как основной источник. Художественная литература дает искаженную, отфильтрованную картину языка.

  • Газеты и периодика: идеальный источник. Местная хроника, объявления, письма в редакцию, реклама. Попробуй Chronicling America (библиотека Конгресса США) или British Newspaper Archive. На 2026 год многие архивы оцифрованы и доступны через API.
  • Судебные протоколы и официальные документы: например, Old Bailey Online. Язык формальный, но насыщенный бытовыми деталями.
  • Личные дневники и письма: сложнее найти в машинночитаемом виде, но существуют коллекции вроде Europeana.
  • Технические руководства и научно-популярные журналы: показывают, как эпоха осмысляла новые технологии.

Цель – собрать 100-500 МБ чистого текста. Этого достаточно для fine-tuning маленькой модели. Текст должен быть одного периода (например, 1898-1902 гг.) и по возможности одного региона, чтобы избежать лингвистического "шума".

# Пример сбора данных через wget с публичного архива
# (Замени URL на актуальные источники на 06.04.2026)
wget -r -l1 -H -nd -A.txt -erobots=off https://archive.example.com/1900-newspapers/

2 Чистим и подготавливаем текст: скучная, но важная магия

Скачанные файлы – это хаос. OCR-ошибки, заголовки, нумерация страниц. Нужно привести все к единому формату. Пиши простой скрипт на Python.

import re
from pathlib import Path

def clean_historical_text(text: str) -> str:
    # Удаляем типичные для сканов артефакты
    text = re.sub(r'\f', ' ', text)  # Разрывы страниц
    text = re.sub(r'\s+', ' ', text)  # Множественные пробелы
    # Удаляем номера страниц в формате "[123]"
    text = re.sub(r'\[\d+\]', '', text)
    # Можно добавить правила для удаления повторяющихся заголовков
    return text.strip()

corpus = []
for txt_file in Path("./raw_data").glob("*.txt"):
    content = txt_file.read_text(encoding='utf-8', errors='ignore')
    cleaned = clean_historical_text(content)
    if len(cleaned) > 100:  # Отбрасываем слишком короткие фрагменты
        corpus.append(cleaned)

# Сохраняем один большой файл для обучения
with open("corpus_1900.txt", "w", encoding="utf-8") as f:
    f.write("\n".join(corpus))
💡
Не удаляй орфографические варианты того времени (например, "черезъ" с твердым знаком). Они – часть языкового колорита. Твой токенизатор должен их учесть. Для современных моделей это может быть проблемой, поэтому иногда эффективнее обучить собственный токенизатор на историческом корпусе, как описано в глубоком руководстве по TimeCapsuleLLM.

3 Выбираем модель-основу: кто поедет в прошлое

На 2026 год выбор компактных моделей огромен. Критерии: открытая лицензия, размер (от 124M до 2B параметров), качество базовой подготовки. Fine-tuning огромной модели на маленьком датасете приведет к катастрофическому забыванию – модель забудет все, кроме твоих исторических текстов.

Модель (актуально на 06.04.2026) Параметры Почему подходит
Qwen2.5-1.5B 1.5 млрд Отличное базовое знание, стабильная архитектура, эффективный токенизатор. Легко адаптируется.
Phi-3-mini (4k) 3.8 млрд Создана Microsoft для эффективного обучения на малых данных. Идеальный кандидат.
Gemma 2-2B 2 млрд Новая версия от Google, оптимизирована для инструктивного тонкого обучения.

Мой выбор для эксперимента – Qwen2.5-1.5B. Она хорошо сбалансирована, имеет современную архитектуру (улучшенный RoPE, SwiGLU) и отзывчива к fine-tuning. Если твое железо скромнее, присмотрись к Phi-2 (2.7B), которая отлично работает даже на CPU, как в нашем кейсе с GTX 1060.

4 Настраиваем окружение и запускаем обучение

Используем библиотеку Hugging Face Transformers (актуальная версия на 2026 год – 4.45.0) с PEFT (Parameter-Efficient Fine-Tuning), конкретно LoRA. Это позволяет обучить только крошечную часть параметров, оставив основную модель нетронутой. Экономит память и время, снижая риск переобучения.

# Установка актуальных библиотек (предполагается Python 3.11+)
pip install torch==2.3.0 --index-url https://download.pytorch.org/whl/cu121  # Для CUDA 12.1
pip install transformers==4.45.0 datasets accelerate peft trl bitsandbytes
from transformers import AutoTokenizer, AutoModelForCausalLM, TrainingArguments
from trl import SFTTrainer
from peft import LoraConfig
import torch

# Загружаем модель и токенизатор
model_name = "Qwen/Qwen2.5-1.5B"
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(model_name,
                                             torch_dtype=torch.bfloat16,
                                             device_map="auto",
                                             trust_remote_code=True)

# Конфигурация LoRA - тренируем только attention layers
peft_config = LoraConfig(
    r=16,  # Rank
    lora_alpha=32,
    lora_dropout=0.05,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
    task_type="CAUSAL_LM",
)

# Подготавливаем датасет. Предполагаем, что у нас есть файл corpus_1900.txt
from datasets import Dataset
texts = open("corpus_1900.txt", "r", encoding="utf-8").readlines()
dataset = Dataset.from_dict({"text": texts})

# Токенизация. Используем разбиение на блоки фиксированной длины.
def tokenize_function(examples):
    return tokenizer(examples["text"], truncation=True, max_length=1024)

tokenized_dataset = dataset.map(tokenize_function, batched=True, remove_columns=["text"])

# Аргументы обучения
# Ключевой момент: маленькая скорость обучения (lr) для тонкой настройки
args = TrainingArguments(
    output_dir="./gpt-1900-output",
    num_train_epochs=3,
    per_device_train_batch_size=2,  # Зависит от памяти GPU
    gradient_accumulation_steps=4,
    warmup_steps=100,
    logging_steps=50,
    learning_rate=2e-5,  # Очень маленький LR!
    fp16=False,
    bf16=True,  # Используем bfloat16 если поддерживается
    save_strategy="epoch",
)

# Тренер
trainer = SFTTrainer(
    model=model,
    args=args,
    train_dataset=tokenized_dataset,
    peft_config=peft_config,
    dataset_text_field="text",
    max_seq_length=1024,
    tokenizer=tokenizer,
)

# Поехали!
trainer.train()

Самая частая ошибка – поставить learning_rate больше 5e-5. Ты же не обучаешь с нуля, а лишь слегка подстраиваешь модель. Большой LR сотрет все предыдущие знания, и на выходе получится каша из исторических текстов без способности к связной генерации. Всегда начинай с малого, например, 1e-5 или 2e-5.

5 Тестируем и запускаем: разговор с призраком эпохи

После обучения сохраняем адаптированные веса LoRA и загружаем их для инференса.

from peft import PeftModel

# Сохраняем LoRA веса
trainer.model.save_pretrained("./gpt-1900-lora-weights")

# Для инференса: загружаем базовую модель и адаптеры
base_model = AutoModelForCausalLM.from_pretrained(model_name, device_map="auto", torch_dtype=torch.bfloat16)
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = PeftModel.from_pretrained(base_model, "./gpt-1900-lora-weights")
model = model.merge_and_unload()  # Объединяем веса для скорости

# Генерация
prompt = "В редакцию газеты. Уважаемый господин редактор, пишу Вам по поводу"
inputs = tokenizer(prompt, return_tensors="pt").to("cuda")
outputs = model.generate(**inputs,
                         max_new_tokens=200,
                         temperature=0.8,
                         do_sample=True,
                         top_p=0.92,
                         repetition_penalty=1.05)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))

Температура (temperature) – твой главный инструмент. Поставь 0.7-0.9 для более творческих, но иногда абсурдных ответов. Для точности и фактуальности (насколько это возможно для модели) снизь до 0.3. Но помни, мы не за фактами, а за стилем.

Что может пойти не так: подводные камни GPT-1900

  • Переобучение за 2 эпохи. Симптом: модель идеально повторяет фразы из датасета, но не может сгенерировать ничего нового. Лечение: увеличь размер датасета, добавьте dropout в LoRA, сократи число эпох до 1-2.
  • Катастрофическое забывание. Модель забыла, как говорить на современном языке и строить грамматически правильные предложения. Причина: слишком большой learning_rate или слишком много шагов обучения. Начинай с низкого LR и используй раннюю остановку.
  • Токенизатор не справляется с архаичной лексикой. Современные токенизаторы разбивают "железнодорожный" на "железн", "##одорож", "##ный". С историческими словами может быть еще хуже. Решение – использовать модели с более щадящим токенизатором (например, BPE на байтах, как в Kakugo) или обучить свой, но это отдельная боль.
  • Нехватка видеопамяти. Даже для 1.5B модели с LoRA нужно 6-8 ГБ. Если не хватает, смотри в сторону 4-битного квантования (bitsandbytes) или выбирай модель меньше, например, Phi-2. Подробности в гайде по компактным моделям.

Частые вопросы (FAQ)

Можно ли использовать этот подход для других языков или периодов?

Абсолютно. Методология универсальна. Собираешь корпус текстов на нужном языке за нужный период (скажем, французская пресса 1920-х), выбираешь базовую модель, обученную на этом языке (например, CamemBERT для французского), и повторяешь шаги. Сложность только в поиске качественных машинночитаемых данных.

Как оценить качество получившейся модели?

Стандартные метрики (перплексия) мало что скажут. Лучший тест – качественный анализ (qual eval). Давай модели промпты в стиле эпохи и смотри, насколько последовательно и стилистически верно она продолжает. Сравнивай выводы с реальными текстами из твоего датасета (но не теми, что были в обучении!). Хороший знак – модель использует характерную лексику и синтаксические конструкции без прямого копирования.

Что дальше? Как развить эксперимент?

Попробуй инструктивное тонкое обучение (Instruction Fine-Tuning). Создай синтетический датасет в формате "инструкция-ответ", где инструкции стилизованы под эпоху ("Напиши письмо кузену о поездке на новом паровозе"), а ответы – сгенерированы твоей же базовой моделью и отобраны или отредактированы. Это превратит модель из генератора текста в подобие диалогового агента эпохи. Но помни о рисках переобучения на синтетике, о которых мы уже предупреждали.

Фишка эксперимента GPT-1900 не в том, чтобы создать полезный продукт. А в том, чтобы на собственной шкуре прочувствовать, как данные формируют сознание модели. Как несколько мегабайт текстов, написанных людьми, умершими сто лет назад, могут перезаписать часть цифрового мозга. Это немного жутко. И невероятно интересно.

Подписаться на канал