Зачем учить модель с нуля в 2026 году?
Все вокруг говорят про финтюн Llama-4 или настройку Gemma-3 через QLoRA. Но представь, что ты можешь создать свою архитектуру с нуля. С нуля. Не дообучить, не адаптировать, а именно создать. Это как разница между сборкой мебели из IKEA и вырезанием стула из цельного куска дерева. Первое - практично. Второе - искусство.
Strawberry - моя экспериментальная микро-модель на 1.8 миллиона параметров. Не 1.8 миллиарда. Миллиона. Она помещается в оперативку телефона, работает на процессоре десятилетней давности, но при этом учится генерировать связный текст. Сегодня я покажу весь процесс: от сбора сырых данных до анализа кривых обучения. Без магии, только код и цифры.
Сбор датасета: что искать, где брать, как фильтровать
Первая ошибка новичков - пытаться накормить модель всем подряд. "Вот 50GB текста из Википедии, пусть учится". Не работает. Модель на 1.8M параметров просто не вместит такое разнообразие. Ей нужна фокусировка.
1 Выбор источников: качество против количества
Для Strawberry я использовал три типа данных:
- Книги в общественном достоянии - Project Gutenberg, но не все подряд. Только англоязычная художественная литература 19-20 веков. Почему? Современный язык слишком сложен для микро-модели.
- Научные статьи по машинному обучению - arXiv, но только abstracts. Полные статьи - перебор для 1.8M параметров.
- Диалоги из фильмов - субтитры с открытых репозиториев. Диалоговая структура помогает модели понять turn-taking.
Предупреждение: Не смешивайте жанры хаотично. Если ваша цель - научный текст, не добавляйте поэзию. Микро-модели не справляются с диссонансом стилей.
2 Очистка данных: что выкидывать без сожаления
Сырые данные - это помойка. Вот что я удалял в первую очередь:
import re
def clean_text(text):
# Удаляем HTML-теги
text = re.sub(r'<.*?>', '', text)
# Удаляем специальные символы (кроме базовой пунктуации)
text = re.sub(r'[^\w\s.,!?\-:\'\"]', '', text)
# Заменяем множественные пробелы на один
text = re.sub(r'\s+', ' ', text)
# Удаляем строки короче 20 символов (скорее всего, мусор)
if len(text) < 20:
return ''
return text.strip()
Но самая важная фильтрация - по длине предложений. Слишком короткие (меньше 3 слов) - шум. Слишком длинные (больше 50 слов) - модель на 1.8M параметров их не "запомнит". Я оставлял предложения от 5 до 30 слов. Жестко? Да. Эффективно? Еще как.
Токенизация: не просто разбить на слова
В 2026 году все еще используют BPE (Byte Pair Encoding). Но для микро-модели стандартный токенайзер - убийство. У вас всего 1024 размера словаря (я использовал именно столько). Каждый токен должен нести максимум смысла.
Вот как выглядит процесс подготовки:
from tokenizers import Tokenizer, models, trainers, pre_tokenizers
from tokenizers.processors import TemplateProcessing
# Создаем BPE токенайзер с нуля
tokenizer = Tokenizer(models.BPE())
# Указываем специальные токены
special_tokens = ["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"]
# Обучаем на нашем датасете
trainer = trainers.BpeTrainer(
vocab_size=1024, # Маленький словарь для микро-модели
special_tokens=special_tokens,
min_frequency=2 # Слово должно встречаться минимум 2 раза
)
# Собираем тексты для обучения токенайзера
training_texts = []
for text_chunk in load_dataset_chunks():
training_texts.append(text_chunk)
tokenizer.train_from_iterator(training_texts, trainer=trainer)
# Добавляем пост-обработку
tokenizer.post_processor = TemplateProcessing(
single="[CLS] $A [SEP]",
pair="[CLS] $A [SEP] $B:1 [SEP]:1",
special_tokens=[
("[CLS]", tokenizer.token_to_id("[CLS]")),
("[SEP]", tokenizer.token_to_id("[SEP]")),
],
)
Архитектура Strawberry: почему именно так
1.8 миллиона параметров - это не много. На самом деле, это смехотворно мало по меркам 2026 года. Но в этой малости - вызов.
| Компонент | Параметры | Обоснование |
|---|---|---|
| Embedding слой | 1024 × 256 = 262,144 | Маленькая размерность эмбеддингов, но достаточная для 1024 токенов |
| Transformer блоки | 4 слоя × ~300K = 1,200,000 | Всего 4 слоя вместо стандартных 12. Качество ниже, но работает |
| Внимание | 4 головы по 64 размерности | Multi-head attention, но упрощенный |
| FFN слой | 256 → 1024 → 256 | Feed-forward network с bottleneck |
| Output слой | 256 × 1024 = 262,144 | Обратно в словарь |
Самое интересное - я использовал Grouped Query Attention (GQA) вместо стандартного MHA. Зачем? Для микро-модели 4 отдельных heads внимания - роскошь. GQA разделяет ключи и значения между группами heads. Экономит 15% параметров без заметной потери качества.
Обучение: цифры, которые имеют значение
Здесь большинство гайдов врут. Или не договаривают. Я покажу реальные цифры из обучения Strawberry:
# Конфигурация обучения Strawberry
training_config = {
"batch_size": 16, # Не 32, не 64. Именно 16.
"context_length": 128, # Длиннее нельзя - памяти не хватит
"total_steps": 50000, # Да, пятьдесят тысяч шагов
"warmup_steps": 1000, # Плавный старт
"learning_rate": 3e-4, # Высокий LR для быстрой сходимости
"weight_decay": 0.01, # Регуляризация обязательна
"gradient_clip": 1.0, # Клиппинг градиентов
}
Почему batch size 16? Потому что на одной RTX 4090 с 24GB памяти это максимум для контекста в 128 токенов. Хочешь batch 32? Уменьшай контекст до 64. Выбирай.
Ошибка, которую делают все: Ставят learning rate 1e-4 потому что "так в бумагах". Для микро-модели нужен более агрессивный LR. 3e-4 работает лучше. Проверено.
3 Мониторинг: train loss vs val loss - где правда
Вот график, который у меня получился после 20к шагов:
Train loss: Плавно снижается с 8.5 до 2.1
Val loss: Снижается с 8.7 до 2.8, затем начинает колебаться
Колебания val loss после 2.8 - это переобучение? Нет. Это предел capacity модели. Она просто не может выучить датасет лучше с 1.8M параметров. Когда видишь, что val loss застрял на одном уровне 5000 шагов подряд - останавливай обучение. Дальше только overfitting.
Интересный момент: perplexity (PPL) на валидации остановился на ~16.5. Что это значит? Модель "не уверена" в следующем слове. Для сравнения: у GPT-4 PPL около 3-5. Но у GPT-4 и параметров в 1000 раз больше.
Что модель реально умеет после обучения
Strawberry не напишет тебе роман. Не решит математическую задачу. Но вот что она делает:
- Генерирует связные предложения на темы из датасета
- Поддерживает простой диалог (в стиле "вопрос-ответ")
- Запоминает и повторяет паттерны из тренировочных данных
- Работает на CPU в реальном времени (10-15 токенов в секунду)
Пример генерации:
Prompt: "The neural network"
Output: "The neural network processes the input data through multiple layers of transformation and attention mechanisms to produce a meaningful output representation."
Не Шекспир, но и не случайный набор слов. Модель уловила стиль научных абстрактов из датасета.
Распространенные ошибки и как их избежать
Ошибка 1: Слишком большой словарь токенов
Видел проекты, где для модели на 2M параметров делали словарь на 50k токенов. Безумие. Каждый токен - это параметры в embedding слое. 50k × 256 = 12.8M параметров только на эмбеддинги! Вся модель - 1.8M. Математика не сходится.
Ошибка 2: Игнорирование OOV (out-of-vocabulary) токенов
В микро-модели каждый токен на счету. Если 30% слов превращаются в [UNK] - вы теряете треть информации. Либо увеличьте словарь, либо предобрабатывайте текст, заменяя редкие слова на синонимы.
Ошибка 3: Обучение без весового decay
Weight decay=0.01 - не опционально. Это обязательно. Без регуляризации микро-модель переобучается за 1000 шагов. Проверено на горьком опыте.
Куда двигаться дальше
Strawberry - только начало. После того как освоите обучение с нуля, можно перейти к более сложным экспериментам. Например, попробовать архитектуру Falcon-H1-Tiny - она оптимизирована для работы на ограниченных ресурсах.
Или если хочется работать с готовыми моделями, но настраивать их под конкретные задачи, изучите NTTuner + GUI для финтюна на Windows. А для создания качественных датасетов есть отдельный гайд про подготовку данных для LoRA.
Но самое интересное - это эксперименты с архитектурой. Что если вместо Transformer использовать Mamba? Или смешанные подходы? В 2026 году BitMamba-2-1B показывает, что альтернативы Transformer могут быть эффективнее.
Когда в следующий раз будете использовать GPT-7 или Claude-4, вспомните - где-то там, на вашем жестком диске, живет маленькая модель на 1.8M параметров, которая понимает только базовые паттерны языка. И это прекрасно.