Навигация: README | Архитектура →
LLM (Large Language Model) — математическая функция:
f(токены на входе) → вероятности следующего токена
Внутри — огромный набор чисел (веса/weights).
Qwen2.5-14B = 14 миллиардов чисел с плавающей точкой.
Модель не думает, не понимает, не знает.
Она предсказывает — какой токен идёт следующим
на основе паттернов из триллионов примеров обучения.
Но это предсказание настолько сложное,
что результат выглядит как понимание.
Аналогия:
Шахматный движок не "понимает" шахматы —
он перебирает позиции и выбирает лучший ход.
LLM не "понимает" язык — перебирает паттерны
и выбирает наиболее вероятное продолжение.
Модель не работает с буквами и не со словами.
Она работает с токенами — кусками текста.
BPE (Byte Pair Encoding) — алгоритм:
Пример:
"привет как дела" →
Токены Qwen2.5 (примерно):
["▁при", "вет", "▁как", "▁дела"]
Каждый токен → число (ID):
"▁при" = 12847
"вет" = 3291
"▁как" = 891
"▁дела" = 5632
Модель работает с числами: [12847, 3291, 891, 5632]
Правило большого пальца:
1 токен ≈ 0.75 слова (английский)
1 токен ≈ 0.5 слова (русский — кириллица дороже)
Примеры:
"Hello world" = 2 токена
"Привет мир" = 4 токена
Страница A4 ≈ 400-600 токенов
Книга 300 страниц ≈ 120,000-180,000 токенов
Контекст 8K токенов ≠ 8000 слов
На русском это ≈ 4000 слов ≈ 8-10 страниц A4
При выборе модели: context_length = максимум токенов
Qwen2.5-14B поддерживает 128K токенов ≈ 250 страниц
Qwen2.5 — это N слоёв трансформера (у 14B ≈ 40 слоёв).
Входной вектор токена [d=5120 чисел]
↓
┌─────────────────────────────────┐
│ RMSNorm │ нормализация
└────────────┬────────────────────┘
↓
┌─────────────────────────────────┐
│ Self-Attention │
│ │
│ Q = token × W_Q "что ищу" │
│ K = token × W_K "что есть" │
│ V = token × W_V "что дать" │
│ │
│ score = Q · K^T / √d │
│ weights = softmax(score) │
│ out = weights × V │
│ │
│ result = out × W_O │
└────────────┬────────────────────┘
↓
+ residual (добавляем вход) ← важно! градиенты текут
↓
┌─────────────────────────────────┐
│ RMSNorm │
└────────────┬────────────────────┘
↓
┌─────────────────────────────────┐
│ Feed-Forward │
│ │
│ h = token × W_1 [d→4d] │ расширение ×4
│ h = SwiGLU(h) │ нелинейность
│ out = h × W_2 [4d→d] │ сжатие обратно
└────────────┬────────────────────┘
↓
+ residual
↓
Выход слоя [d=5120 чисел]
Self-Attention позволяет каждому токену
"смотреть" на все другие токены в контексте.
Пример:
"Кот сидит на коврике. Он мурлычет."
Токен "Он" должен понять что он = кот, не коврик.
Self-Attention вычисляет:
- score("Он", "Кот") = 0.89 ← высокий
- score("Он", "коврике") = 0.12 ← низкий
→ "Он" получает информацию от "Кот"
→ модель понимает кореференцию
Feed-Forward — это "память фактов".
Attention находит КАКИЕ токены важны.
FF решает ЧТО с ними делать — применяет знания.
Исследования показали:
- Attention слои хранят синтаксис и структуру
- FF слои хранят факты и знания о мире
Матрица — это прямоугольная таблица чисел.
W_Q для 14B модели:
Размер: 5120 × 5120 = 26,214,400 чисел
Каждое число: float16 = 2 байта
Размер в памяти: ~50MB
Всего матриц в 14B: ~240
Суммарно: ~28GB в FP16, ~7GB в Q4
Знания НЕ хранятся как база данных:
❌ W[1024][512] = "Париж — столица Франции"
Знания хранятся как геометрия пространства:
✅ Паттерн весов такой, что:
вектор("Франция") + вектор("столица")
→ после умножения на матрицы →
ближайший токен = "Париж"
Это распределённое представление.
Нет одного нейрона = "Париж".
Есть паттерн активации тысяч нейронов.
Qwen2.5: d_model слоёв параметров
─────────────────────────────────────
7B: 3584 28 7B
14B: 5120 40 14B
72B: 8192 80 72B
Больше d_model → более богатое представление токенов
Больше слоёв → более глубокие абстракции
Шаг 1: Токенизация
"Привет!" → [14823, 1] (2 токена)
Шаг 2: Embedding
Каждый токен → вектор [5120 чисел]
из таблицы embeddings (словарь → вектор)
Шаг 3: Прогон через 40 слоёв
[5120] → Layer_1 → [5120] → Layer_2 → ... → Layer_40 → [5120]
Шаг 4: LM Head (языковая голова)
[5120] × W_lm_head → [152000 чисел] (размер словаря)
Шаг 5: Softmax
[152000] → вероятности для каждого токена
"Привет" = 0.0001
"Как" = 0.34 ← высокая
"дела" = 0.28
...
Шаг 6: Sampling
Выбираем токен с учётом temperature:
temperature=0: всегда берём максимум ("Как")
temperature=1: случайно по вероятностям
temperature=2: больше рандома
Результат: токен "Как" → добавляем в контекст
Шаг 7: Повторить с новым контекстом
до токена <END> или max_tokens
Каждый токен зависит от всех предыдущих.
Нельзя генерировать параллельно.
Это главное ограничение скорости LLM.
Контекст = плоский массив токенов который видит модель.
[системный промпт][история чата][текущий вопрос]
↑ ↑ ↑
всегда на входе прошлые ответы новый запрос
Всё это умещается в контекстное окно.
Qwen2.5-14B: до 128,000 токенов.
Контекст полный → старые сообщения удаляются (sliding window)
→ или ошибка если жёсткий лимит
→ или суммаризация (если настроено)
Модель не помнит что было ДО текущего контекста.
Каждый вызов — чистый лист если не передавать историю.
При каждом шаге генерации нужны K и V матрицы
для всех предыдущих токенов.
Без KV-cache: пересчитывать K,V для ВСЕХ токенов на каждом шаге
→ O(n²) сложность → очень медленно
С KV-cache: K,V вычислены один раз → сохранены в RAM
→ O(n) сложность → быстро
Цена KV-cache:
14B, 4K контекст: ~1GB RAM
14B, 32K контекст: ~8GB RAM
14B, 128K контекст: ~32GB RAM
Qwen2.5-14B полный (FP32): 14B × 4 байта = 56GB ← не влезет
Qwen2.5-14B (FP16): 14B × 2 байта = 28GB ← нужно много RAM
Qwen2.5-14B (Q4_K_M): 14B × 0.5 байта ≈ 7GB ← оптимально!
Q8_0 — 8 бит, потеря ~1%, ÷2 размер
Q6_K — 6 бит, потеря ~2%, ÷2.7 размер
Q5_K_M — 5 бит, потеря ~2%, ÷3.2 размер
Q4_K_M — 4 бит, потеря ~3-5%, ÷4 размер ← ЛУЧШИЙ ВЫБОР
Q3_K_M — 3 бит, потеря ~7%, ÷5 размер
Q2_K — 2 бит, потеря ~15%, ÷6 размер ← плохо
Рекомендация: Q4_K_M
- ÷4 меньше памяти
- только ~3-5% потери качества
- поддерживается llama.cpp / Ollama
FP16 вес: 0.3847656 (16 бит, точно)
Q4 вес: 6 (4 бита, 0-15)
+ масштаб блока: 0.0256
Восстановление: 6 × 0.0256 = 0.1536 (≈ но не точно)
Потеря точности ≈ 3-5% на типичных задачах.
На практике: почти незаметна при Q4_K_M.
tok/s ≈ RAM_bandwidth / model_size_in_bytes
Почему:
Для каждого токена нужно прочитать ВСЕ веса модели
(прогнать данные через все 240 матриц)
Qwen2.5-14B Q4 = 7GB
Нужно читать 7GB на каждый токен
Конфигурация Bandwidth tok/s (14B Q4)
─────────────────────────────────────────────────────────
Старый ноутбук DDR3 2-ch 25 GB/s ~3 tok/s
Современный ПК DDR4 2-ch 42 GB/s ~5 tok/s
Б/У сервер DDR4 4-ch 60 GB/s ~8 tok/s
Б/У сервер DDR4 8-ch 85 GB/s ~12 tok/s
Mac Mini M4 unified memory 120 GB/s ~17 tok/s
RTX 3090 GDDR6X (24GB) 936 GB/s ~130 tok/s ← если влезает
Без AVX2: llama.cpp использует скалярные операции
С AVX2: vectorized операции, ×1.5-2 быстрее
AVX2 появился в:
- Intel Haswell (2014) — 4-е поколение Core, Xeon v3
- AMD Ryzen (2017) — все современные AMD
Проверить: grep avx2 /proc/cpuinfo
GPU:
+ В 10-100× быстрее
- Модель должна ВЛЕЗАТЬ в VRAM
- RTX 3090 24GB → до 20B Q4
CPU:
+ Любой размер RAM
+ Дешевле
- Медленнее
- Нужно AVX2
Гибрид (GPU+CPU offloading):
- Часть слоёв на GPU, часть на CPU
- Ollama делает это автоматически
Специальный токен-блок в начале контекста
который задаёт "личность" и правила поведения.
Контекст модели:
[<|system|>
Ты краткий ассистент. Отвечай по делу.
<|/system|>]
[<|user|>
Что такое Python?
<|/user|>]
[<|assistant|>] ← модель генерирует отсюда
При обучении (SFT) модель видела миллионы примеров:
[system: "Ты учитель"] → подробные объяснения
[system: "Ты кодер"] → короткий код без объяснений
[system: "Ты враг"] → плохие ответы
Модель ВЫУЧИЛА: содержимое [system] = правила игры
Личность: "Ты краткий технический ассистент"
Стиль: "Отвечай только кодом, без объяснений"
Язык: "Всегда отвечай по-русски"
Ограничения: "Не обсуждай политику"
Формат: "Используй Markdown, код в блоках"
Роль: "Ты старший разработчик Python"
Контекст: "Мы работаем над Drupal сайтом..."
НЕ меняет веса модели — только направляет
НЕ гарантирует поведение — модель может отклониться
НЕ добавляет знания — только стиль ответов
НЕ работает как код — это просто текст
LLM = большая матрица весов (14B чисел)
+ алгоритм умножения (трансформер)
+ квантизация (уменьшить до 7GB)
+ движок (llama.cpp внутри Ollama)
Скорость ≈ RAM bandwidth / размер модели
Качество ≈ количество параметров × качество обучения
Поведение = системный промпт + fine-tuning
Для локального AI нужно:
1. Достаточно RAM (модель + KV-cache)
2. Быстрая память (DDR4, желательно много каналов)
3. AVX2 процессор (Haswell 2014+)
4. Ollama как движок
5. Системный промпт для личности
Следующий документ: 02_ARCHITECTURE.md