docs: add README, architecture, glossary, requirements; update CLAUDE.md

Add four Russian-language project documents:
- README.md: user-facing guide (install, quick start, data prep, training,
  evaluation, limitations)
- docs/architecture.md v1.0: system architecture, data flow diagrams,
  module interfaces, 7 architectural decision records, extension points
- docs/glossary.md v1.0: musical, ML, and project-specific term definitions
- docs/requirements.md v1.0: functional/non-functional requirements,
  acceptance criteria, four use-case scenarios

Update CLAUDE.md with project name etymology (hamori / ハモリ) and rename
repo root reference from chord-gen to hamori. Refine chord_format_spec.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-19 11:00:21 +03:00
parent 9929209bcf
commit 75fa07bf6c
6 changed files with 2312 additions and 5 deletions
+915
View File
@@ -0,0 +1,915 @@
# Архитектура системы hamori
**Версия документа:** 1.0
**Дата:** 2026-05-19
Документ описывает архитектуру проекта _hamori_ — генератора гармонических
периодов: высокоуровневую структуру, потоки данных, состав модулей, ключевые
проектные решения и их обоснование, а также точки расширения.
---
## Содержание
1. [Высокоуровневая архитектура](#1-высокоуровневая-архитектура)
2. [Потоки данных](#2-потоки-данных)
3. [Состав модулей](#3-состав-модулей)
4. [Модель машинного обучения](#4-модель-машинного-обучения)
5. [Конвейер обучения](#5-конвейер-обучения)
6. [Конвейер инференса и оценки](#6-конвейер-инференса-и-оценки)
7. [Ключевые проектные решения](#7-ключевые-проектные-решения)
8. [Точки расширения](#8-точки-расширения)
---
## 1. Высокоуровневая архитектура
Система состоит из шести логических уровней.
**Уровень человекочитаемых данных.** Текстовые `.chord`-файлы лид-шит-нотации,
с которыми работает автор-композитор при ручной транскрипции. Каждый файл
описывает один гармонический период.
**Уровень парсинга и валидации.** Модули, преобразующие `.chord`-файлы в
структурированные внутренние представления и проверяющие их корректность.
**Уровень токенизации.** Модули, преобразующие структурированные представления
в последовательности целочисленных идентификаторов и обратно. Здесь же
выполняется нормализующая транспозиция в каноническую тональность.
**Уровень обучения и инференса.** Реализация нейросетевой модели, циклы
обучения и сэмплирования, работа с чекпоинтами.
**Уровень оценки.** Расчёт метрик, построение распределений, формирование
графических артефактов для отчёта.
**Уровень внешних адаптеров.** Конвертеры публичных корпусов в формат `.chord`,
экспорт периодов в MIDI.
Схема информационных связей между уровнями:
```
автор-композитор
.chord-файлы (raw_user)
│ публичный корпус
│ │
│ ▼
│ внешний конвертер
│ │
│ ▼
│ .chord-файлы (raw_external)
│ │
└────────┬────────┘
парсер + валидатор
транспозиция в C/Am
токенизатор
.pt-файлы (processed)
┌──────────────────┼──────────────────┐
▼ ▼ ▼
train выборка val выборка holdout выборка
│ │ │
└────────┬─────────┘ │
▼ │
трансформер: pre-train + fine-tune │
│ │
▼ │
чекпоинты ◄───────────────────────┘
│ │
┌────────────────┼────────────────────────────┘
▼ ▼
инференс оценка
│ │
▼ ▼
.chord + MIDI метрики + графики + образцы
│ │
▼ ▼
автор-композитор отчёт
```
---
## 2. Потоки данных
### 2.1 Поток подготовки собственного корпуса
```
DAW-проект (REAPER)
│ ручная транскрипция
.chord-файл в data/raw_user/
│ валидация формата
│ (опционально: MIDI-санитарная проверка)
.chord-файл прошёл проверку
│ скрипт prepare_data.py
│ ├── чтение
│ ├── транспозиция в C major / A minor
│ ├── токенизация
│ └── разбиение train / val
.pt-файлы в data/processed/user/{train,val}/
```
### 2.2 Поток подготовки публичного корпуса
```
McGill Billboard (Harte-аннотации)
│ скрипт mcgill_to_chord.py
│ ├── парсинг Harte-нотации
│ ├── разрезание на периоды по секциям
│ ├── определение тональности
│ └── конвертация в .chord
.chord-файлы в data/raw_external/mcgill_converted/
│ скрипт prepare_data.py
.pt-файлы в data/processed/mcgill/{train,val}/
```
### 2.3 Поток обучения
```
data/processed/mcgill/ ◄── предобучение
checkpoints/pretrained.pt
│ инициализация весов
data/processed/user/ ◄── дообучение
checkpoints/finetuned.pt
```
### 2.4 Поток инференса
```
пользовательские параметры (CLI)
│ построение prompt-токенов
│ ▼
prompt = <BOS> + метатокены + опциональный prefix
│ авторегрессионная генерация (top-p sampling)
последовательность токенов до <EOS>
│ детокенизация
ChordPeriod в канонической тональности C/Am
│ транспозиция в целевую тональность
ChordPeriod в требуемой тональности
│ сериализация + MIDI-экспорт
.chord и .mid файлы
```
### 2.5 Поток оценки
```
data/processed/holdout/
вычисление перплексии для base и target
извлечение признаков (типы аккордов, инверсии, интервалы корня)
построение гистограмм и таблиц
reports/figures/, reports/metrics.json
```
---
## 3. Состав модулей
### 3.1 `src/chord_parser.py`
**Назначение.** Разбор отдельных аккордовых символов в строго типизированное
представление.
**Публичный интерфейс.**
- `parse_chord_symbol(symbol: str) -> ChordTokens` — парсит строку вида `Am7`,
`Cmaj9`, `F/G`, `Bb7b9/D` в dataclass `ChordTokens(root, quality, extension, bass)`.
- `ChordParseError` — исключение, поднимаемое при невалидном символе.
**Ключевые соображения реализации.** Модуль не использует регулярные
выражения для парсинга качеств: вместо этого выполняется последовательное
распознавание из таблицы альтернативных написаний по принципу самого длинного
совпадения. Это упрощает добавление новых качеств в будущем и снижает риск
тонких ошибок с приоритетами совпадений.
Бемольные написания корня и баса нормализуются к диезной форме на этапе парсинга.
**Связи.** Используется модулем `tokenizer.py` для разбора аккордов внутри
периода. Не имеет зависимостей внутри проекта, кроме стандартной библиотеки
Python и опционально `music21` (как fallback для нетипичных написаний).
### 3.2 `src/tokenizer.py`
**Назначение.** Преобразование `.chord`-файлов в последовательности
целочисленных идентификаторов и обратно. Реализация словаря токенов.
Реализация нормализующей транспозиции.
**Публичный интерфейс.**
- Константа `VOCAB: list[str]` — словарь токенов в порядке, описанном в
спецификации формата (81 токен).
- Константа `TOKEN_TO_ID: dict[str, int]` — обратное отображение.
- Функция `parse_chord_file(path: Path) -> ChordPeriod` — парсинг
`.chord`-файла в структурированное представление.
- Функция `transpose_to_canonical(period: ChordPeriod) -> ChordPeriod`
транспозиция мажорных периодов в C major, минорных в A minor.
- Функция `tokenize_period(period: ChordPeriod) -> list[int]` — последовательно
выполняет транспозицию и преобразование в токены.
- Функция `detokenize_to_period(token_ids: list[int]) -> ChordPeriod`
обратная операция, возвращает период в канонической тональности.
- Функция `transpose_period(period, target_key) -> ChordPeriod`
транспозиция в произвольную целевую тональность (используется на этапе
инференса для возврата результата в требуемую тональность).
- Исключение `ChordFormatError` — для ошибок формата файла.
**Ключевые соображения реализации.** Словарь токенов является константой
модуля; его изменение приводит к несовместимости с ранее обученными моделями,
поэтому любые изменения должны сопровождаться инкрементом версии спецификации
формата и переобучением моделей.
Транспозиция реализуется через расчёт интервала в полутонах между исходным и
целевым тонами, после чего к каждому корневому тону и бассу применяется
циклический сдвиг по 12-тоновой системе. Качество и расширения аккорда при
транспозиции не меняются.
**Связи.** Используется всеми остальными модулями для входа и выхода из
токенизированного пространства. Зависит от `chord_parser.py`.
### 3.3 `src/midi_export.py`
**Назначение.** Преобразование `.chord`-файлов в стандартные MIDI-файлы для
прослушивания в DAW и для использования сгенерированных периодов в
композиторской работе.
**Публичный интерфейс.**
- `chord_file_to_midi(chord_path, midi_path, tempo=90)` — основная функция.
- `period_to_midi(period: ChordPeriod, midi_path, tempo=90)` — вариант,
принимающий уже распарсенный период.
**Ключевые соображения реализации.** MIDI-файл содержит два инструментальных
трека: трек аккордов и трек баса. Аккорды раскладываются в средней октаве
(C4–B5) тремя или четырьмя одновременными нотами, бас — в нижней октаве (C2–B2)
одной нотой. Длительности соответствуют длительностям удержания аккордов в
исходном `.chord`-файле.
Voicing внутри аккорда выполняется минимально — простое расположение нот в
тесном расположении от корня. Это не задача данного модуля и сознательно
оставлено простым.
**Связи.** Зависит от `tokenizer.py` (для парсинга `.chord`) и `pretty_midi`.
### 3.4 `src/dataset.py`
**Назначение.** Реализация PyTorch-датасета над предварительно
токенизированными `.pt`-файлами.
**Публичный интерфейс.**
- Класс `ChordDataset(torch.utils.data.Dataset)`.
- Конструктор принимает путь к директории с `.pt`-файлами и максимальную
длину последовательности.
- `__getitem__` возвращает тензор токенов, обрезанный или дополненный
паддингом до максимальной длины.
- Функция `make_dataloader(dataset, batch_size, shuffle) -> DataLoader`
удобная фабрика.
**Ключевые соображения реализации.** Все `.pt`-файлы загружаются в память при
создании датасета. Это допустимо при текущем размере данных (тысячи периодов
максимум) и существенно ускоряет обучение по сравнению с подгрузкой с диска.
Паддинг выполняется специальным токеном `<PAD>` с индексом 2 в словаре.
В функции потерь этот индекс игнорируется через параметр `ignore_index`.
### 3.5 `src/model.py`
**Назначение.** Определение нейросетевой архитектуры.
**Публичный интерфейс.**
- Класс `ChordTransformer(nn.Module)` с параметрами конструктора:
`vocab_size`, `d_model`, `n_layers`, `n_heads`, `d_ff`, `max_seq_len`,
`dropout`.
**Архитектурные детали.** Декодер-only трансформер с pre-normalization
(нормализация перед остаточной связью, а не после). Эмбеддинги токенов и
позиционные эмбеддинги — обучаемые. Веса входного эмбеддинга и финальной
проекции на словарь связаны (tied weights), что сокращает число параметров
и стабилизирует обучение на малых данных.
Каждый блок трансформера состоит из:
- LayerNorm
- Causal multi-head self-attention с маскированием будущих позиций
- Residual connection
- LayerNorm
- Feedforward с активацией GELU
- Residual connection
После последнего блока — финальная LayerNorm и линейная проекция на размер
словаря.
**Связи.** Используется в модулях обучения и инференса.
### 3.6 `src/train.py`
**Назначение.** Логика обучения, общая для предобучения и дообучения.
**Публичный интерфейс.**
- Функция `train_model(config: TrainConfig) -> Path` — основная точка
входа. Возвращает путь к лучшему чекпоинту.
- Dataclass `TrainConfig` с полями для всех гиперпараметров.
**Особенности.** Один общий цикл обучения параметризуется аргументом
`init_from`. Если этот аргумент задан, веса модели инициализируются из
указанного чекпоинта, иначе — случайно. Это позволяет использовать один и
тот же код для предобучения и дообучения, различающихся только параметрами
запуска (низкий learning rate, меньшее число эпох для дообучения).
Логирование: после каждой эпохи в stdout выводится строка с номером эпохи,
тренировочной потерей, валидационной потерей и валидационной перплексией.
Параллельно строка добавляется в CSV-лог. Лучший по валидационной потере
чекпоинт сохраняется отдельно.
Ранняя остановка: если валидационная потеря не улучшается на протяжении N
эпох (по умолчанию 5), обучение завершается досрочно.
### 3.7 `src/generate.py`
**Назначение.** Сэмплирование из обученной модели.
**Публичный интерфейс.**
- Функция `generate_period(model, mode, time, subdivision, style, function,
key, prefix=None, temperature=1.0, top_p=0.9, max_tokens=300, seed=None)
-> ChordPeriod`.
**Ключевые соображения реализации.** Авторегрессионная генерация выполняется
по одному токену за раз. Для каждого шага:
1. Прогон последовательности через модель, получение распределения над
следующим токеном.
2. Деление логитов на температуру.
3. Применение nucleus sampling: оставляем минимальный по числу элементов
набор кандидатов с накопленной вероятностью не менее top_p.
4. Маскирование грамматически невалидных кандидатов (например, токена
расширения сразу после токена удержания).
5. Сэмплирование из оставшегося распределения.
6. Останов при появлении `<EOS>` или при достижении лимита токенов.
После завершения генерации последовательность детокенизируется, получившийся
период транспонируется из канонической тональности в целевую и возвращается
вызывающему.
### 3.8 `src/evaluate.py`
**Назначение.** Расчёт метрик качества и построение распределений.
**Публичный интерфейс.**
- `compute_perplexity(model, dataloader) -> float`.
- `extract_features(period: ChordPeriod) -> dict` — извлекает гармонические
признаки периода: список типов качеств, доли инверсий, интервалы движения
корня, биграммы корней.
- `compare_distributions(baseline_features, target_features) -> dict` —
агрегирует признаки и формирует структуры для построения графиков.
- `plot_comparison(distributions, output_dir)` — рисует и сохраняет графики.
### 3.9 `src/external_converters/mcgill_to_chord.py`
**Назначение.** Конвертация аннотаций McGill Billboard Project в формат
`.chord`.
**Публичный интерфейс.**
- `convert_directory(input_dir, output_dir, log_path=None)` — конвертирует
все пьесы из исходной директории.
- `convert_song(song_dir, output_dir) -> list[Path]` — конвертирует одну
пьесу, возвращает список путей к созданным файлам периодов.
**Ключевые соображения реализации.** Harte-нотация McGill отличается от
формата проекта по ряду признаков: использует другие имена качеств, явно
указывает интервальный состав в скобках, имеет иную систему обозначения
длительностей. Конвертер реализует таблицу соответствий между Harte и форматом
проекта и приводит к ближайшему допустимому аккорду в случаях, когда точное
соответствие отсутствует.
Разрезание на периоды выполняется по разметке секций в исходных файлах
(`verse`, `chorus`, `bridge` и т.д.). Периоды длиной менее 4 или более 16
тактов пропускаются.
---
## 4. Модель машинного обучения
### 4.1 Выбор архитектуры
Архитектура декодер-only трансформера выбрана по следующим причинам.
**Соответствие задаче.** Гармоническая последовательность — это
последовательность дискретных символов с сильными локальными
зависимостями (соседние аккорды связаны функциональными отношениями) и
менее сильными глобальными зависимостями (начало и конец периода связаны
тонально). Self-attention отражает оба типа зависимостей естественным
образом.
**Совместимость со схемой предобучения + дообучения.** Архитектуры
семейства трансформеров — стандартный выбор для задач с малой целевой
выборкой и большим объёмом предобучающих данных.
**Простота реализации с нуля.** При выбранном масштабе модели (несколько
блоков, небольшая размерность) реализация умещается в нескольких сотнях
строк кода и не требует тяжёлых зависимостей.
Альтернатива в виде LSTM была рассмотрена и отвергнута на основании того,
что:
- При сопоставимом числе параметров трансформер обычно работает не хуже на
задачах с дискретными последовательностями.
- Параллелизация обучения трансформера эффективнее.
- Стандартное предобучение языковых моделей через next-token prediction
легче переносится на трансформер, чем на рекуррентные сети.
### 4.2 Параметры модели
Размер модели сознательно выбран небольшим — порядка одного-трёх миллионов
параметров. Это обусловлено объёмом обучающих данных: при тысячах примеров
крупная модель неизбежно переобучится, а компактная сохранит способность
к обобщению. Рекомендуемая конфигурация:
| Параметр | Значение |
| ---------------------------- | ----------- |
| Число слоёв | 3 |
| Размерность модели (d_model) | 192 |
| Число голов внимания | 6 |
| Размерность FFN | 768 |
| Длина контекста | 512 токенов |
| Размер словаря | 81 |
| Dropout | 0.1 |
При необходимости конфигурация может быть пересмотрена в сторону уменьшения
(если модель не сходится) или увеличения (если результаты явно недостаточны
и есть запас времени на эксперимент).
### 4.3 Функция потерь и оптимизация
Стандартная кросс-энтропия с игнорированием `<PAD>`-токена. Оптимизатор —
AdamW. Расписание learning rate — косинусное снижение с линейным разогревом
на 5% от общего числа шагов.
**Предобучение.** Стартовый learning rate 3·10⁻⁴, 50 эпох (с возможностью
ранней остановки).
**Дообучение.** Стартовый learning rate 1·10⁻⁵, 15 эпох с ранней остановкой.
Двухпорядковая разница в learning rate между предобучением и дообучением —
ключевой приём для предотвращения катастрофического забывания: на этапе
дообучения веса модели изменяются медленно, что сохраняет общие
гармонические закономерности, выученные на крупном корпусе.
### 4.4 Генерация
Используется nucleus sampling (top-p) с температурой 1.0 по умолчанию.
Параметры регулируются на этапе инференса.
Beam search отвергнут на основании опыта генеративных задач: он склонен
порождать монотонные, многократно повторяющиеся последовательности, что
особенно нежелательно в задаче создания творческих идей.
---
## 5. Конвейер обучения
### 5.1 Подготовка данных
```
сырьё (.chord)
парсинг и валидация
транспозиция в каноническую тональность
токенизация
случайное разбиение на train/val (90/10)
сохранение .pt-файлов
```
Разбиение train/val выполняется на уровне периодов, а не на уровне исходных
пьес. Для собственного корпуса это компромиссное решение: разбиение по
пьесам было бы методологически чище, но при 20–25 пьесах привело бы к
слишком высокой дисперсии валидационной потери. Holdout-выборка, в свою
очередь, специально формируется на уровне пьес, что обеспечивает честность
итоговой оценки.
### 5.2 Цикл предобучения
```
инициализация модели случайными весами
для каждой эпохи (1..50):
├── проход по train: forward, loss, backward, optimizer step
│ │
│ ▼
│ агрегация train_loss за эпоху
├── проход по val (без градиентов): forward, loss
│ │
│ ▼
│ агрегация val_loss и val_perplexity
├── запись строки в CSV-лог
├── если val_loss улучшилась — сохранение чекпоинта
└── если val_loss не улучшалась 5 эпох подряд — выход
```
### 5.3 Цикл дообучения
Идентичен циклу предобучения по структуре, отличается:
- Инициализация модели из чекпоинта предобучения.
- Меньший learning rate.
- Меньшее максимальное число эпох (15).
- Опционально: меньший patience для ранней остановки.
### 5.4 Контроль качества обучения
В процессе обучения отслеживаются следующие признаки нормального хода:
- Train loss монотонно снижается.
- Val loss снижается синхронно с train loss до точки, после которой
начинается расхождение (типичное переобучение). Лучший чекпоинт
сохраняется до точки расхождения.
- Val perplexity на сошедшейся модели находится в диапазоне 2–6 для нашей
задачи. Существенно меньшие значения указывают на ошибку (например,
пересечение train и val выборок). Существенно большие — на плохую
сходимость или несоответствие модели данным.
Если эти признаки нарушаются, необходимо в первую очередь проверить
корректность подготовленных данных: токенизацию случайных файлов руками,
отсутствие пересечений между выборками, баланс распределения метаданных.
---
## 6. Конвейер инференса и оценки
### 6.1 Инференс
Подробное описание процесса генерации приведено в разделе 3.7. Ключевые
особенности:
- Все параметры запроса передаются через CLI-аргументы.
- Случайное зерно фиксируется, что обеспечивает воспроизводимость отдельных
семплов.
- Невалидные грамматические последовательности маскируются на каждом шаге
сэмплирования.
- Результат сразу сохраняется в двух форматах: `.chord` (для возможного
редактирования или подачи модели как затравки в дальнейшем) и MIDI (для
прослушивания).
### 6.2 Количественная оценка
**Перплексия** на отложенной выборке рассчитывается как экспонента средней
кросс-энтропии. Сравнение перплексий базовой и целевой моделей на одной
выборке показывает, насколько сильно дообучение сместило распределение
вероятностей модели в сторону распределения собственного корпуса автора.
Снижение перплексии на отложенной выборке после дообучения является
основным численным индикатором успеха проекта. Ожидаемая величина снижения —
от 10% до 50% относительно базовой модели.
### 6.3 Качественная оценка через распределения
Качественная сторона эффекта дообучения оценивается через сравнение
гистограмм по следующим признакам.
**Типы качеств аккордов.** Распределение по 18 базовым качествам. На малых
данных авторский стиль часто проявляется в смещении этого распределения:
например, повышенная частота больших септаккордов и нонаккордов или,
напротив, преобладание простых трезвучий.
**Доля инверсий.** Процент аккордов с явно указанным басом, отличным от
корня. Этот признак особенно характерен для индивидуального стиля и для
конкретных жанров (J-Pop, например, активно использует слэш-аккорды).
**Интервалы движения корня.** Распределение интервалов между корнями
соседних аккордов в полутонах. Например, доминирование интервала –5
полутонов (квинтовый ход вниз) характерно для барочной и классической
гармонии; преобладание интервалов –2, +2 — для более поп-ориентированных
стилей.
**Биграммы корней.** Частоты пар «текущий корень → следующий корень». Эти
биграммы захватывают функциональные предпочтения автора: например,
характерные переходы IV → V или V → vi.
Графики строятся как наложение двух гистограмм (baseline-распределение и
target-распределение) на одной координатной плоскости. Визуальный сдвиг
target относительно baseline — прямое подтверждение того, что дообучение
сработало.
### 6.4 Качественная оценка через прослушивание
Для отчёта формируются три специально подобранные («cherry-picked») пары
сгенерированных образцов: для каждой из выбранных гармонических затравок —
по одному примеру от базовой и от дообученной модели с одним и тем же
случайным зерном. Эти примеры конвертируются в MIDI и прилагаются к отчёту
(в виде ссылок и описаний).
Слепой listening-тест с привлечением сторонних слушателей не проводится из
соображений ограничения по времени.
---
## 7. Ключевые проектные решения
В этом разделе фиксируются проектные решения, принятые на этапе
проектирования, и обоснования к ним. Решения изложены в виде записей в
стиле Architectural Decision Records.
### 7.1 ПР-01. Юнит обработки — гармонический период, а не пьеса целиком
**Контекст.** Изначально рассматривался вариант обучения модели на целых
пьесах. При объёме собственного корпуса 20–25 пьес и средней длине каждой
40–100 тактов это давало бы датасет из 20–25 длинных последовательностей —
крайне малый объём для генеративной модели.
**Решение.** Единицей обработки и генерации является гармонический период —
замкнутая фраза 4–16 тактов. Из одной пьесы извлекается 4–8 периодов.
**Последствия.**
- Эффективный объём датасета увеличивается в 4–8 раз.
- Проблема обработки модуляций между секциями исчезает: внутри периода
модуляций нет.
- Длина обучающей последовательности становится меньшей и более однородной
(50–250 токенов вместо 500–1500), что упрощает обучение.
- Юнит хорошо соответствует реальному композиторскому воркфлоу: помощник
выдаёт идеи периодами, а не целыми пьесами.
### 7.2 ПР-02. Нормализующая транспозиция в C major / A minor
**Контекст.** Если каждый период хранится в исходной тональности,
функционально эквивалентные последовательности в разных тональностях
становятся для модели разными последовательностями. Это резко увеличивает
эффективное разнообразие данных в 12 раз и затрудняет обобщение.
**Решение.** Перед токенизацией все периоды транспонируются: мажорные — в
C major, минорные — в A minor. Тональность в словарь модели не входит.
На инференсе результат транспонируется обратно в требуемую тональность
постпроцессингом.
**Последствия.**
- Эффективное увеличение датасета в 12 раз.
- Сокращение словаря на 24 токена.
- Цвет конкретной тональности (характерное звучание Fis-dur против C-dur)
теряется. Это исполнительское свойство, не функционально-гармоническое,
и для задачи генерации прогрессий не релевантно.
- Внутренние модуляции и тонизации записываются обычными функциональными
аккордами и обрабатываются единообразно.
### 7.3 ПР-03. Факторизованная токенизация аккордов
**Контекст.** Каждый аккорд можно представить либо одним атомарным токеном
(`Cmaj7`, `Am7`, `F/G` как отдельные элементы словаря), либо разложенным
на несколько токенов (корень, качество, расширение, бас).
**Решение.** Каждый аккорд представляется ровно четырьмя токенами:
`ROOT_x`, `QUAL_x`, `EXT_x`, `BASS_x`. Словарь содержит 81 токен против
нескольких сотен в случае атомарной токенизации.
**Последствия.**
- Существенно меньший словарь, легче обучаемый на малых данных.
- Модель видит общность между, например, всеми минорными септаккордами,
а не учит их как 12 несвязанных слов.
- Каждый аккорд занимает в последовательности четыре позиции вместо одной,
что увеличивает длину последовательности и нагрузку на attention. При
выбранной длине контекста 512 это не создаёт проблем.
- Появляется необходимость грамматического маскирования при генерации:
не любой токен может следовать за любым.
### 7.4 ПР-04. Двухстадийное обучение
**Контекст.** Прямое обучение модели на собственном корпусе автора
невозможно из-за крайне малого объёма данных.
**Решение.** Двухстадийная схема: предобучение на крупном публичном
корпусе (McGill Billboard Project) и последующее дообучение на собственном
корпусе с пониженным learning rate.
**Последствия.**
- Базовые гармонические закономерности (функциональная гармония,
стандартные каденции) выучиваются на этапе предобучения.
- Индивидуальный стиль автора подмешивается на этапе дообучения без
необходимости заново выучивать общие законы.
- Появляется естественная схема сравнения «до и после» дообучения для
отчёта.
- Существует риск катастрофического забывания на этапе дообучения, что
митигируется низким learning rate и небольшим числом эпох.
### 7.5 ПР-05. Минималистичная реализация без тяжёлых фреймворков
**Контекст.** Существует ряд готовых фреймворков для обучения трансформеров
(PyTorch Lightning, HuggingFace Trainer, fastai), которые скрывают
boilerplate кода тренировочного цикла.
**Решение.** Использовать чистый PyTorch с явным циклом обучения.
**Последствия.**
- Код полностью прозрачен и поддаётся пошаговой отладке, что важно для
учебного проекта.
- Снижается риск проблем с совместимостью версий и сложным поведением
фреймворков «из коробки».
- Объём кода тренировочного цикла остаётся небольшим (порядка двух сотен
строк).
- Теряется доступ к некоторым удобствам фреймворков (готовые callbacks,
логирование в TensorBoard и т.п.). Для масштабов проекта это
несущественно.
### 7.6 ПР-06. Ручная транскрипция собственного корпуса
**Контекст.** Альтернатива — автоматическое извлечение аккордов из аудио
с помощью библиотек вроде Chordino, librosa, или нейросетевых детекторов.
**Решение.** Транскрипция выполняется автором вручную, на основе
DAW-проектов с использованием абсолютного слуха.
**Последствия.**
- Качество транскрипции существенно выше автоматического: тонкие гармонические
решения, нестандартные расширения, точные инверсии — всё это передаётся
без потерь.
- Существенные временные затраты (10–15 часов). Это самая трудозатратная
часть проекта.
- Невозможность масштабирования на большой корпус. Для текущей задачи
(80–150 периодов) это приемлемо.
### 7.7 ПР-07. Английский язык в коде, русский — в документации и отчёте
**Контекст.** Учебное заведение требует оформления отчёта на русском
языке. С другой стороны, стандарты разработки и совместимость с
инструментами вроде Claude Code предполагают английский язык в коде.
**Решение.** Чёткое разделение по слоям:
- Код, идентификаторы, комментарии, сообщения логов, коммиты — английский.
- Документация (README, спецификация, требования, архитектура,
глоссарий) — русский.
- Итоговый отчёт — русский с оформлением по ГОСТу.
**Последствия.** Однозначность для всех участников разработки.
Двуязычность не создаёт неудобств, поскольку слои разделены.
---
## 8. Точки расширения
Перечисленные ниже направления развития проекта оставлены явно за рамками
текущей версии. Их реализация может рассматриваться в будущем.
### 8.1 Дообучение на корпусе японской поп-музыки
**Описание.** После защиты курсовой работы планируется собрать второй
авторский корпус — гармонические периоды из японских поп-песен (Royal Road
прогрессии, mu-аккорды, характерные секундовые надстройки, on-аккорды) — и
выполнить дополнительное дообучение модели на этом материале с тегом
`STYLE_jpop`.
**Что уже подготовлено для этого расширения.** В словаре токенов
зарезервирован токен `STYLE_jpop`. Формат `.chord` поддерживает любые
характерные для J-Pop приёмы (расширенные аккорды, инверсии, слэш-аккорды).
В шапке файла предусмотрено поле `style`.
**Что нужно дополнительно сделать.** Собрать и транскрибировать корпус
J-Pop периодов. Выполнить дообучение существующей модели на смешанном
корпусе (свой + J-Pop) или последовательное дообучение (свой → J-Pop).
Сравнить генерации с разными значениями стилевого conditioning.
### 8.2 Генерация мелодии
**Описание.** Расширение модели на генерацию монофонической мелодической
линии, привязанной к гармонической последовательности.
**Что нужно сделать.** Расширить формат `.chord` дополнительным полем для
мелодической линии (или ввести отдельный формат). Расширить словарь
токенов мелодическими токенами (вероятно, через раздельное представление
ступени, длительности, артикуляции). Архитектура модели может остаться
прежней.
**Сложность.** Существенная: задача мелодизации сложнее, чем гармонизации,
требует больше данных, имеет другие критерии оценки.
### 8.3 Voicing внутри аккорда
**Описание.** Автоматическое расположение нот внутри аккорда выше баса
с учётом голосоведения (минимизация суммарного движения голосов, запрет
параллельных квинт и октав, разрешение тяготеющих ступеней).
**Что нужно сделать.** Эта задача может быть решена rule-based методом без
машинного обучения. Простой алгоритм минимизации суммарного межаккордового
смещения голосов с дополнительными правилами укладывается в несколько
сотен строк кода.
**Сложность.** Низкая, выполнима за день-два после защиты курсовой.
### 8.4 Графический пользовательский интерфейс
**Описание.** Веб- или десктоп-приложение, позволяющее задавать параметры
генерации интерактивно, прослушивать результат прямо в браузере, сохранять
понравившиеся варианты.
**Что нужно сделать.** Любой современный веб-фреймворк (FastAPI на backend,
любой минимальный frontend) поверх существующего CLI. Воспроизведение
MIDI в браузере через `Tone.js` или подобные библиотеки.
**Сложность.** Невысокая по нынешним стандартам, но требует существенного
времени.
### 8.5 Интеграция с REAPER
**Описание.** Плагин или внешний инструмент, который при работе в REAPER
позволяет запрашивать генерацию следующего фрагмента прямо из проекта,
учитывая текущий гармонический контекст.
**Сложность.** REAPER предоставляет ReaScript для расширений на Lua и
Python. Реализация возможна, но требует погружения в API REAPER.
### 8.6 Обработка модуляций внутри периода
**Описание.** Текущая версия требует разрезания периодов по точке
модуляции. Альтернатива — введение inline-токена `MODULATE_<note>_<mode>`,
переключающего тонический центр в середине последовательности.
**Что нужно сделать.** Расширить словарь токенов на 24 модуляционных
токена. Дополнить парсер и токенизатор поддержкой inline-меток модуляции.
Накопить достаточное число обучающих примеров с модуляциями (что
проблематично при малом исходном корпусе).
**Сложность.** Средняя, основное ограничение — данные.
### 8.7 Поддержка большего числа альтераций в аккорде
**Описание.** Текущая версия поддерживает один слот расширения на аккорд.
Альтерированные доминанты с несколькими альтерациями одновременно
(`C7♯9♭13`) сворачиваются до одной альтерации.
**Что нужно сделать.** Перейти от единственного `EXT_x` токена к множеству
одновременных токенов расширений. Это требует пересмотра грамматики
последовательности и формата представления одного аккорда (теперь его
описание становится не четырёхтокеновым, а переменной длины).
**Сложность.** Средняя, в основном проектная — требуется аккуратное
обновление формата с инкрементом версии.
---
## 9. История изменений
- **1.0** (2026-05-19) — первоначальная редакция документа.
+1 -3
View File
@@ -1,6 +1,4 @@
# Спецификация формата данных
## Проект: генератор аккордовых последовательностей
# Спецификация формата данных hamori
**Версия:** 2.0
**Дата:** 2026-05-16
+567
View File
@@ -0,0 +1,567 @@
# Глоссарий hamori
**Версия документа:** 1.0
**Дата:** 2026-05-19
Документ содержит определения терминов, используемых в проекте _hamori_,
разделённые на три тематические группы: музыкальные термины, термины
машинного обучения и проектные термины. Внутри каждой группы записи
упорядочены по алфавиту.
---
## 1. Музыкальные термины
### Аккорд
Гармоническая единица — одновременное звучание трёх и более нот. В контексте
проекта аккорд представляется в текстовой нотации (например, `Cmaj7`, `Am`,
`F/G`) и характеризуется четырьмя признаками: корневой тон, качество,
расширение, бас.
### Аккордовая последовательность (прогрессия)
Последовательность аккордов, сопровождающая мелодию или существующая
самостоятельно. Является основным объектом генерации в данном проекте.
### Альтерация
Хроматическое изменение ступени аккорда — повышение или понижение её на
полутон. В рамках формата проекта альтерации записываются как расширения
вида `b9`, `#9`, `#11`, `b13`.
### Анакруза (затакт)
Несколько нот или один аккорд, предшествующих первой сильной доле такта.
В формате проекта затакт записывается через специальное значение `NC`
(no chord) на пустых позициях первого такта.
### Бас
Самая нижняя нота аккорда. Может совпадать с корневым тоном (основной
позиции) или отличаться от него (в инверсиях и слэш-аккордах). В формате
проекта бас выделен в отдельный слот токенизации.
### Гармоническая функция
Роль аккорда в тональной системе: тоника (T), субдоминанта (S), доминанта
(D) и их побочные ступени. Хотя в формате проекта аккорды записываются
абсолютными именами, а не функциональными цифрами, нормализующая
транспозиция в C major / A minor делает функциональные роли явно читаемыми:
после транспозиции `C` всегда тоника мажорной пьесы, `A` — тоника
минорной.
### Гармонический период
Замкнутая гармоническая фраза длиной обычно 4, 8 или 16 тактов, имеющая
ясное начало и завершение (возврат к тонике или полукаденция). Является
**единицей обработки и генерации** в проекте.
### Голосоведение
Способ соединения нот в соседних аккордах: плавное движение голосов,
запрет параллельных квинт и октав, разрешение тяготеющих ступеней.
В текущей версии проекта голосоведение **не моделируется**
сгенерированные аккорды передаются как абстрактные гармонические единицы,
а конкретное расположение голосов оставлено на ручную работу композитора
в DAW.
### Доминанта
Аккорд пятой ступени лада. Содержит вводный тон и создаёт сильное
тяготение к тонике. Обычная запись в виде доминантового септаккорда — `G7`
в C major, `E7` в A minor (с альтерированной третьей ступенью минора).
### Инверсия (обращение)
Аккорд, в котором в качестве баса выступает не корневой тон, а одна из
других нот аккорда (терция, квинта, септима). В формате проекта инверсии
записываются через слэш-нотацию: `C/E` (C мажор с басом E, первое
обращение), `C/G` (с басом G, второе обращение).
### Каденция
Гармонический оборот, завершающий музыкальную фразу. Полная каденция —
переход доминанты в тонику (V → I). Полукаденция — остановка на
доминанте, создающая ожидание продолжения. Полукаденция — характерный
признак середины периода в классических формах.
### Качество (тип) аккорда
Интервальная структура аккорда независимо от его корневого тона. Базовые
качества, поддерживаемые форматом проекта: мажорное и минорное трезвучия,
уменьшённое и увеличенное трезвучия, sus2 и sus4, мажорный, минорный,
доминантовый, полууменьшённый и уменьшённый септаккорды, минорно-мажорный
септаккорд, доминанта на sus4, увеличенный септаккорд, мажорный и минорный
аккорды с секстой, аккорды с добавленной ноной. Всего 18 качеств.
### Корневой тон
Основная нота, на которой строится аккорд. Не обязательно совпадает с
басом (см. _Инверсия_). В формате проекта корневой тон выделен в отдельный
слот токенизации.
### Лад
Структурно-функциональная организация звуков вокруг центра (тоники).
В проекте моделируются два лада: натуральный мажор и натуральный минор
(включая гармонический и мелодический миноры как разновидности — отдельно
не различаются). Лад фиксируется отдельным метатокеном `MODE_major` или
`MODE_minor`.
### Лид-шит-нотация
Способ записи музыки, при котором над тактами выписывается мелодия, а
гармония указывается аккордовыми символами без точной нотации каждой ноты
аккорда. Формат `.chord` в проекте — упрощённый аналог лид-шита,
содержащий только гармоническую часть.
### Минор гармонический
Разновидность минорного лада с повышенной седьмой ступенью, создающая
выраженную доминанту. Внутренние альтерации (V становится мажорным,
появляется уменьшённый VII7) трактуются в формате проекта как обычные
аккорды.
### Модуляция
Смена тональности в произведении. В рамках текущей версии формата
поддерживается только модуляция **между периодами** (каждый период
хранится в своей тональности). Модуляция **внутри периода** обрабатывается
через разрезание периода на два — до и после момента модуляции.
### Нонаккорд
Аккорд, расширенный девятой ступенью от корня. В формате проекта —
`Cmaj9` (мажорный септаккорд + натуральная нона), `C9` (доминантовый
септаккорд + нона), `Cm9` (минорный септаккорд + нона), `Cmaj7#11` (с
повышенной квартой), и другие. Записывается как качество + расширение в
слоте `EXT`.
### Подразделение доли (subdivision)
Параметр формата, определяющий, на сколько временных позиций делится один
такт. При `subdivision: 4` в размере 4/4 каждый такт делится на четыре
четверти (четыре позиции). При `subdivision: 8` — на восемь восьмых
(восемь позиций). Выбирается в зависимости от того, как часто меняются
аккорды в конкретной пьесе.
### Полиаккорд
Одновременное звучание двух функционально различных аккордов в разных
регистрах (например, мажорное трезвучие D-F♯-A над мажорным трезвучием
C-E-G). В текущей версии формата полиаккорды **не поддерживаются**.
Близкие по звучанию структуры записываются через слэш-нотацию (`C/D`,
`F/G`) или ближайший один аккорд с расширениями.
### Расширение аккорда
Дополнительный интервал, надстраивающийся над септаккордом: нона (9),
ундецима (11), терцдецима (13), с возможными альтерациями (`b9`, `#9`,
`#11`, `b13`). В формате проекта расширение записывается одним токеном
в отдельном слоте `EXT`. Поддерживается ровно один слот расширения на
аккорд.
### Royal Road progression
Характерная гармоническая прогрессия японской популярной музыки:
IV — V — iii — vi (например, в C major: `F → G → Em → Am`). Прогрессия
ассоциируется с мелодичной, ностальгической эмоциональной окраской и
встречается в значительной части анисонга и J-Pop в широком смысле.
### Sus-аккорды
Аккорды с задержанной квартой (sus4) или секундой (sus2), заменяющей
терцию. Лишены терцового тона, не определены как мажорные или минорные.
В формате проекта — `Csus4`, `Csus2`, а также `C7sus4` (доминантовый
септаккорд на sus4, часто встречается перед разрешением в обычный
доминантовый аккорд).
### Слэш-аккорд (slash chord, on-аккорд)
Аккорд с явно указанным басом, отличным от любой ноты собственного состава.
Записывается как `<аккорд>/<бас>`. Характерный приём японской поп-музыки:
`F/G`, `C/D`, `Em7/A` — обеспечивают плавное движение баса и характерное
напряжение.
### Тактовый размер
Соотношение числа долей в такте и их длительности. В формате проекта
поддерживаются `4/4`, `3/4`, `6/8`, `2/4`, `12/8`. Большинство периодов
ожидается в размере `4/4`.
### Тональность
Конкретное положение лада на звукоряде, определяемое тоникой и видом
лада (`F# major`, `B♭ minor`, `C major`). В формате `.chord` указывается
в шапке файла полем `key`. Перед обучением модели все периоды
нормализуются в C major / A minor; в словарь модели тональность не
входит.
### Тонизация (отклонение)
Кратковременный заход в другую тональность через её собственную доминанту
без полноценной модуляции. Например, в C major последовательность
`Dm — A7 — Dm` содержит тонизацию D minor. В формате проекта тонизации
записываются обычными аккордовыми символами и не требуют специальной
разметки.
### Тоника
Главный устойчивый тон лада, опора. В формате после нормализующей
транспозиции тоника — `C` для мажорных периодов и `A` для минорных.
### Функциональная роль периода
Роль данного периода в форме исходной пьесы: куплет, припев, пре-припев,
бридж, вступление, проигрыш, концовка. В формате `.chord` указывается в
шапке поле `function`. Передаётся в модель как метатокен `FUNC_x` и может
использоваться как conditioning на инференсе.
---
## 2. Термины машинного обучения
### Авторегрессионная модель
Модель, генерирующая последовательность по одному элементу за раз, причём
каждый следующий элемент условен на всех предыдущих. Декодер-only
трансформер, используемый в проекте, — пример авторегрессионной модели.
### Beam search
Алгоритм поиска наиболее вероятной последовательности при генерации:
вместо сэмплирования удерживается несколько лучших кандидатов на каждом
шаге, выбирается итоговая последовательность с максимальной совместной
вероятностью. В проекте **не используется**, поскольку для генеративных
творческих задач даёт монотонные результаты.
### Catastrophic forgetting (катастрофическое забывание)
Феномен, при котором при дообучении модели на новом наборе данных она
теряет знания, выученные на исходном корпусе. В проекте митигируется
существенным снижением скорости обучения на этапе дообучения и
ограничением числа эпох.
### Causal mask (причинная маска)
Маска внимания в декодер-only трансформере, не позволяющая каждой позиции
«видеть» будущие позиции в последовательности. Обеспечивает корректное
обучение задачи предсказания следующего токена.
### Cross-entropy loss
Функция потерь, измеряющая расхождение между предсказанным моделью
распределением вероятностей следующего токена и истинным значением. Стандартная
функция потерь для задач классификации и генерации последовательностей.
### Декодер-only трансформер
Архитектура нейросети, состоящая из стека одинаковых блоков, каждый из
которых содержит self-attention с причинной маской и feedforward-слой.
В отличие от encoder-decoder архитектуры, у декодер-only нет отдельного
блока для кодирования входа — всё обрабатывается одной башней. GPT-семейство
языковых моделей — наиболее известный пример. Используется в данном проекте.
### Дообучение (fine-tuning)
Адаптация модели, ранее обученной на большом корпусе, к конкретной задаче
или домену через дополнительное обучение на меньшем целевом наборе данных.
В проекте после предобучения на McGill Billboard модель дообучается на
собственном корпусе автора.
### Embedding (эмбеддинг)
Числовое векторное представление дискретного элемента (токена). В трансформере
эмбеддинги токенов и позиций суммируются и подаются в первый блок. Размерность
эмбеддинга равна размерности модели (`d_model`).
### Epoch (эпоха)
Один полный проход обучающего цикла по всем элементам тренировочной выборки.
В проекте предобучение длится до 50 эпох с ранней остановкой,
дообучение — до 15.
### Holdout (отложенная выборка)
Часть данных, отделённая до начала обучения и не используемая ни в
тренировочной, ни в валидационной выборках. Применяется только для итоговой
оценки качества модели. В проекте формируется на уровне исходных пьес
(не на уровне периодов), что обеспечивает методологическую честность
сравнения.
### LayerNorm (нормализация слоя)
Нормализующее преобразование, стабилизирующее распределение активаций
внутри сети. В архитектуре проекта применяется в pre-norm варианте
(перед residual connection, не после).
### Learning rate
Скорость обучения, коэффициент шага оптимизатора. В проекте используется
значение `3e-4` на этапе предобучения и `1e-5` на этапе дообучения —
двухпорядковая разница принципиальна для предотвращения катастрофического
забывания.
### Logits
Выход модели перед применением softmax — нормализованные числовые
оценки, отражающие предпочтения модели по каждому возможному следующему
токену. Используются в функции потерь и в процессе сэмплирования.
### Multi-head attention
Механизм self-attention, в котором операция внимания выполняется
параллельно несколькими «головами», каждая со своими обучаемыми
проекциями. Результаты голов конкатенируются. В проекте используется
6 голов.
### Nucleus sampling (top-p sampling)
Стратегия сэмплирования, при которой на каждом шаге сохраняется
минимальный по числу элементов набор кандидатов с накопленной
вероятностью не менее заданного порога `p`, после чего из этого набора
происходит сэмплирование. Применяется в проекте с `p = 0.9` по умолчанию.
### Padding
Дополнение коротких последовательностей до фиксированной длины специальным
токеном. В проекте — токен `<PAD>` (индекс 2 в словаре), игнорируемый в
функции потерь через параметр `ignore_index`.
### Perplexity (перплексия)
Метрика качества языковой модели, рассчитываемая как экспонента средней
кросс-энтропии. Содержательно — «эффективное число равновероятных
альтернатив», между которыми модель колеблется на каждом шаге. Чем
меньше, тем лучше. В проекте используется как основная численная метрика
сравнения базовой и дообученной моделей.
### Positional embedding (позиционный эмбеддинг)
Векторное представление позиции токена в последовательности, добавляемое
к токеновому эмбеддингу. Позволяет модели учитывать порядок элементов
(сам по себе self-attention перестановочно-инвариантен). В проекте
используются обучаемые позиционные эмбеддинги.
### Pre-norm vs post-norm
Два варианта размещения LayerNorm в блоке трансформера: до residual
connection (pre-norm) или после (post-norm). Pre-norm обычно более
стабилен при обучении. В проекте используется pre-norm.
### Предобучение (pre-training)
Этап обучения модели на большом и общем по содержанию корпусе данных,
после которого следует адаптация модели к более узкой задаче или домену.
В проекте предобучение выполняется на McGill Billboard Project.
### Ранняя остановка (early stopping)
Приём, прекращающий обучение, когда метрика на валидационной выборке
перестаёт улучшаться на протяжении заданного числа эпох. Предотвращает
переобучение. В проекте используется с параметром терпения 5 эпох.
### Round-trip эквивалентность
Свойство пары взаимно обратных преобразований: при последовательном
применении прямого и обратного преобразования исходное представление
восстанавливается с точностью до канонической нормализации. В проекте
требуется для пары «парсинг + токенизация / детокенизация + сериализация»
и проверяется автоматизированными тестами.
### Self-attention
Механизм внимания, в котором последовательность взаимодействует сама с
собой: для каждой позиции рассчитываются взвешенные средние значений с
других позиций, веса определяются скалярными произведениями обучаемых
проекций. Центральный элемент архитектуры трансформера.
### Softmax с температурой
Модификация softmax, в которой логиты предварительно делятся на
параметр температуры. При температуре больше 1 распределение становится
более равномерным (генерация разнообразнее), при меньше 1 — более
концентрированным (генерация консервативнее). По умолчанию в проекте — 1.0.
### Tied weights (связанные веса)
Приём, при котором веса входного эмбеддинга и финальной проекции на
словарь совпадают (одна и та же матрица). Снижает число параметров и
часто улучшает обобщающую способность. Применяется в проекте.
### Токен
Элементарная единица обработки модели — целочисленный идентификатор
из конечного словаря. В данном проекте словарь содержит 81 токен,
обозначающих служебные значения, метаданные периода и компоненты
аккордов.
### Токенизация
Преобразование исходного представления данных в последовательность
токенов. В проекте — преобразование `.chord`-файла в последовательность
целочисленных идентификаторов.
### Тренировочная и валидационная выборки (train / val)
Разбиение обучающих данных: тренировочная выборка используется для
обновления весов модели, валидационная — для контроля переобучения и
выбора лучшего чекпоинта. В проекте используется разбиение 90/10. Кроме
того, отдельно выделяется отложенная выборка (см. _Holdout_).
### Warmup (разогрев)
Начальная фаза обучения, в течение которой learning rate линейно растёт
от нуля до целевого значения. Стабилизирует обучение трансформеров на
первых шагах. В проекте — 5% от общего числа шагов.
### Чекпоинт
Сохранённое на диск состояние модели (веса, конфигурация, опционально
состояние оптимизатора), пригодное для возобновления обучения или для
инференса. В проекте сохраняются чекпоинты `pretrained.pt` и
`finetuned.pt`.
---
## 3. Проектные термины
### `.chord`-файл
Текстовый файл в формате, описанном в `docs/chord_format_spec.md`. Содержит
шапку с метаданными периода и тело — последовательность тактов с
аккордовыми символами. Один файл = один гармонический период.
### hamori
Название проекта. Транслитерация японского слова ハモリ, означающего
вокальную гармонизацию — практику добавления второго или третьего голоса
к основной мелодической линии в певческом ансамбле. Само слово образовано
от глагола ハモる (_hamoru_) — «гармонизировать», в свою очередь
заимствованного из английского _harmony_. Название отражает основную
функциональную идею проекта: модель не пишет музыку с нуля, а предлагает
гармонические идеи в дополнение к замыслу композитора.
### BAR (токен)
Служебный токен, отмечающий конец такта в токенизированной
последовательности. Помогает модели усваивать ритмическую сетку периода.
### `<BOS>`, `<EOS>`, `<PAD>`, `<UNK>`
Служебные токены словаря: начало последовательности, конец последовательности,
паддинг и неизвестный токен соответственно.
### `ChordTokens`
Dataclass, представляющий разобранный аккорд: четыре строковых поля —
`root`, `quality`, `extension`, `bass`. Является промежуточным
представлением между текстовым аккордовым символом и токенами модели.
### `ChordPeriod`
Dataclass, представляющий полностью разобранный гармонический период:
метаданные шапки и список тактов, каждый из которых — список позиций.
Является промежуточным представлением между `.chord`-файлом и токенами.
### `ChordFormatError` / `ChordParseError`
Типы исключений, поднимаемые при некорректном формате файла или
некорректном аккордовом символе соответственно. Содержат информативные
сообщения с указанием места ошибки.
### EXT (расширение)
Один из четырёх слотов токенизации аккорда. Кодирует расширение аккорда:
`EXT_none` (расширения нет), `EXT_9`, `EXT_b9`, `EXT_#9`, `EXT_11`,
`EXT_#11`, `EXT_13`, `EXT_b13`. Восемь возможных значений.
### FUNC (функциональная роль)
Метатокен периода, указывающий на функциональную роль в исходной пьесе.
Возможные значения: `FUNC_verse`, `FUNC_chorus`, `FUNC_prechorus`,
`FUNC_bridge`, `FUNC_intro`, `FUNC_outro`, `FUNC_interlude`, `FUNC_other`,
`FUNC_unspecified`.
### HOLD (токен)
Служебный токен, означающий, что текущая позиция продолжает звучание
предыдущего аккорда. Использование `HOLD` существенно сокращает длину
последовательности по сравнению с повторением всех четырёх токенов
аккорда.
### MODE (лад)
Метатокен периода, указывающий на лад. Только два значения: `MODE_major`
для мажора и `MODE_minor` для минора. После нормализующей транспозиции
этот токен — единственный носитель информации о ладе в обучающих данных.
### NC (No Chord)
Специальное значение позиции, обозначающее паузу в гармонии — отсутствие
аккорда. Применяется, например, в анакрузах. Имеет соответствующий
служебный токен `NC` в словаре.
### Нормализующая транспозиция
Преобразование, переводящее любой период в каноническую тональность:
мажорные периоды — в C major, минорные — в A minor. Применяется перед
токенизацией. На инференсе обратное преобразование возвращает результат
в требуемую пользователем тональность.
### Период (см. также _Гармонический период_ в музыкальной части)
Единица обработки и генерации в проекте. Замкнутая гармоническая фраза
4–16 тактов, представленная одним `.chord`-файлом.
### QUAL (качество)
Один из четырёх слотов токенизации аккорда. Кодирует качество аккорда:
`QUAL_maj`, `QUAL_m`, `QUAL_dim`, `QUAL_aug`, `QUAL_sus2`, `QUAL_sus4`,
`QUAL_maj7`, `QUAL_m7`, `QUAL_7`, `QUAL_m7b5`, `QUAL_dim7`, `QUAL_mM7`,
`QUAL_7sus4`, `QUAL_aug7`, `QUAL_6`, `QUAL_m6`, `QUAL_add9`,
`QUAL_m_add9`. Восемнадцать возможных значений.
### ROOT (корень)
Один из четырёх слотов токенизации аккорда. Кодирует корневой тон:
`ROOT_C`, `ROOT_C#`, ..., `ROOT_B`. Двенадцать возможных значений.
### BASS (бас)
Один из четырёх слотов токенизации аккорда. Кодирует басовый тон:
`BASS_root` (бас совпадает с корнем) или конкретная нота
(`BASS_C`, `BASS_C#`, ..., `BASS_B`). Тринадцать возможных значений.
### Стилевой тег (STYLE)
Метатокен периода, указывающий на стилистическую принадлежность.
Возможные значения: `STYLE_user` (собственный корпус автора), `STYLE_jpop`
(японская поп-музыка), `STYLE_classical` (классическая музыка),
`STYLE_jazz` (джазовая музыка), `STYLE_other` (прочее, включая публичные
корпуса вроде McGill Billboard). Может использоваться как conditioning
на инференсе.
### SUB (подразделение доли)
Метатокен периода, указывающий, как делится такт на временные позиции.
Возможные значения: `SUB_4` (по четвертям) и `SUB_8` (по восьмым).
### TIME (тактовый размер)
Метатокен периода, указывающий тактовый размер. Возможные значения:
`TIME_4/4`, `TIME_3/4`, `TIME_6/8`, `TIME_2/4`, `TIME_12/8`.
### Шапка файла
Часть `.chord`-файла, содержащая метаданные периода. Строки шапки
начинаются с символа `#` и имеют вид `# key: value`. Шапка обязательно
содержит поля `title`, `key`, `time`, `subdivision`, `style` и
опционально — `function`.
---
## 4. История изменений
- **1.0** (2026-05-19) — первоначальная редакция документа.
+467
View File
@@ -0,0 +1,467 @@
# Требования к проекту hamori
**Версия документа:** 1.0
**Дата:** 2026-05-19
Документ описывает функциональные и нефункциональные требования к проекту
_hamori_ — генератору гармонических периодов в авторском композиторском
стиле. Описываются ограничения, критерии приёмки и явно выведенные за рамки
возможности.
---
## 1. Контекст и цели проекта
### 1.1 Постановка задачи
Разработать генеративную нейросетевую модель, способную создавать
гармонические последовательности заданной длины и стилистики, обученную в
том числе на корпусе собственных произведений автора, с целью использования
получившейся модели как творческого инструмента в композиторской работе.
### 1.2 Заинтересованные стороны
| Сторона | Интерес |
| ------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| Автор-разработчик (студент) | Закрытие курсовой дисциплины, получение работающего инструмента для собственной композиторской практики |
| Преподаватель курса | Демонстрация владения полным циклом ML-проекта: постановка задачи, подготовка данных, обучение, оценка, интерпретация |
| Потенциальные читатели исходного кода | Понимание принятых архитектурных решений и возможность повторного использования компонентов |
### 1.3 Учебные цели
Демонстрация компетенций в следующих областях машинного обучения:
- Проектирование задачи генерации последовательностей в условиях ограниченного
объёма обучающих данных.
- Выбор и реализация архитектуры авторегрессионной модели для дискретных
последовательностей.
- Подготовка и токенизация специализированного датасета.
- Применение схемы предобучение / дообучение.
- Количественная и качественная оценка генеративной модели.
- Анализ распределений и интерпретация результатов.
### 1.4 Прикладные цели
Получение программного инструмента, обладающего следующими функциональными
характеристиками:
- Принимает на вход параметры желаемой гармонической последовательности.
- Принимает опциональную гармоническую затравку из нескольких аккордов.
- Генерирует последовательность аккордов, согласованную с заданными параметрами
и стилистически приближенную к авторскому корпусу.
- Сохраняет результат в формате, пригодном для непосредственного использования
в цифровой звуковой рабочей станции.
---
## 2. Ограничения
### 2.1 Временные ограничения
Жёсткий срок реализации: менее одного календарного месяца с момента начала
работ. Бюджет ручного труда автора: около 50 часов.
Распределение времени:
- Подготовка инфраструктуры данных: ~12 часов.
- Ручная транскрипция собственного корпуса: ~10–15 часов.
- Реализация модели и обучение: ~12 часов.
- Оценка и подготовка примеров: ~6 часов.
- Написание отчёта и оформление: ~10 часов.
### 2.2 Ресурсные ограничения
Аппаратные ресурсы: персональный ноутбук автора. Использование облачных
GPU-ресурсов (Google Colab) допустимо, но не должно быть критически
необходимым — модель проектируется так, чтобы обучение было выполнимо на CPU.
Программные ресурсы: открытое программное обеспечение, бесплатные публичные
датасеты.
### 2.3 Ограничения по данным
Объём собственного корпуса автора ограничен числом существующих
композиторских работ и временем, доступным на ручную транскрипцию.
Реалистичный ориентир: 80–150 гармонических периодов из 20–25 пьес.
Это значение на два-три порядка меньше типичного объёма данных, на которых
обучаются современные музыкальные генеративные модели. Из этого ограничения
вытекает принципиальное архитектурное решение: модель должна использовать
схему «предобучение на публичном корпусе плюс дообучение на собственном
корпусе», обучение с нуля исключительно на собственных данных нецелесообразно.
### 2.4 Языковые требования
Согласно требованиям учебного заведения:
- Итоговый отчёт оформляется на русском языке по стандартам ГОСТ для
студенческих работ.
- Документация для пользователя (README, спецификация формата, описания
архитектуры) ведётся на русском языке.
- Технические артефакты кода (идентификаторы, комментарии, сообщения логов,
сообщения коммитов) ведутся на английском языке для совместимости с
общепринятыми стандартами разработки и удобства совместной работы с
инструментами вроде Claude Code.
---
## 3. Функциональные требования
### 3.1 Подсистема работы с форматом данных
**ФТ-1.** Система должна поддерживать чтение `.chord`-файлов в формате,
описанном в `docs/chord_format_spec.md` версии 2.0, включая:
- Парсинг шапки с метаданными.
- Парсинг тела файла, состоящего из последовательности тактов.
- Распознавание аккордовых символов по правилам §4 спецификации.
- Поддержку всех восемнадцати базовых качеств аккордов с альтернативными
написаниями.
- Поддержку расширений аккордов (одиночный слот).
- Поддержку слэш-нотации для инверсий.
- Распознавание специальных значений (точка для удержания, `NC` для паузы,
`?` для неизвестного аккорда).
**ФТ-2.** Система должна выполнять валидацию `.chord`-файлов:
- Проверять корректность шапки (все обязательные поля присутствуют, значения
входят в допустимые множества).
- Проверять, что число позиций в каждом такте соответствует тактовому
размеру и подразделению доли.
- Поднимать информативные ошибки с указанием имени файла, номера такта и
позиции при обнаружении нарушений.
**ФТ-3.** Система должна выполнять нормализующую транспозицию:
все мажорные периоды приводятся к тональности C major, минорные — к A minor.
**ФТ-4.** Система должна выполнять токенизацию `.chord`-файлов в
последовательности целочисленных идентификаторов согласно словарю,
описанному в §5 спецификации формата. Словарь содержит 81 токен.
**ФТ-5.** Система должна поддерживать обратную детокенизацию: преобразование
последовательности целочисленных идентификаторов обратно в `.chord`-файл,
с последующей опциональной транспозицией в произвольную тональность.
**ФТ-6.** Система должна обеспечивать round-trip эквивалентность: для
любого корректного `.chord`-файла операция `parse → tokenize → detokenize →
serialize` должна давать `.chord`-файл, эквивалентный исходному по
гармоническому содержанию.
### 3.2 Подсистема экспорта в MIDI
**ФТ-7.** Система должна обеспечивать экспорт `.chord`-файлов в стандартный
формат MIDI с двумя треками: трек аккордов и трек баса. Темп задаётся
параметром, по умолчанию 90 ударов в минуту.
**ФТ-8.** Длительности нот в MIDI должны соответствовать длительностям
удержания аккордов в исходном `.chord`-файле.
### 3.3 Подсистема конвертации внешних корпусов
**ФТ-9.** Система должна предоставлять конвертер McGill Billboard Project →
формат `.chord`, выполняющий:
- Чтение Harte-нотации.
- Разрезание исходных пьес на гармонические периоды по границам секций.
- Сохранение каждого периода как отдельного `.chord`-файла.
- Простановку стилевого тега и функциональной роли в шапке.
**ФТ-10.** Конвертер должен быть устойчив к некорректным или неполным
аннотациям в исходном корпусе: периоды, которые не могут быть однозначно
сконвертированы, пропускаются с записью в лог, выполнение скрипта при этом
не прерывается.
### 3.4 Подсистема обучения
**ФТ-11.** Система должна реализовывать архитектуру авторегрессионного
трансформера со следующими параметрами:
- Количество слоёв: настраиваемое, 2–4 по умолчанию.
- Размерность модели: настраиваемая, 128–256 по умолчанию.
- Число голов внимания: настраиваемое, 4–8 по умолчанию.
- Контекстное окно: 512 токенов.
- Связанные веса входного и выходного эмбеддингов.
**ФТ-12.** Система должна предоставлять единый скрипт обучения, параметризуемый
аргументами командной строки, поддерживающий:
- Обучение модели с нуля (предобучение).
- Дообучение существующей модели (fine-tuning) — через параметр инициализации
весов из указанного чекпоинта.
- Настройку всех ключевых гиперпараметров через аргументы.
- Установку случайного зерна для воспроизводимости.
- Автоматический выбор вычислительного устройства (CPU/GPU) с возможностью
принудительного задания.
**ФТ-13.** В процессе обучения система должна:
- Логировать значения функции потерь на тренировочной и валидационной
выборках после каждой эпохи.
- Логировать перплексию на валидационной выборке.
- Сохранять лучший по валидационной потере чекпоинт.
- Поддерживать раннюю остановку по валидационной потере с настраиваемым
параметром терпения.
- Сохранять полный лог обучения в формате CSV.
### 3.5 Подсистема инференса
**ФТ-14.** Система должна предоставлять CLI-инструмент генерации со
следующими настраиваемыми параметрами:
- Путь к чекпоинту модели.
- Лад (мажор / минор).
- Тональность (любой из 12 классов высоты).
- Тактовый размер.
- Подразделение доли.
- Стилевой тег.
- Функциональная роль.
- Опциональная гармоническая затравка (последовательность аккордовых символов).
- Температура сэмплирования.
- Параметр top-p (nucleus sampling).
- Максимальное число токенов.
- Случайное зерно.
- Пути для сохранения `.chord`- и MIDI-файлов.
**ФТ-15.** Инференс должен использовать nucleus sampling с настраиваемой
температурой. Beam search не используется.
**ФТ-16.** Система должна предотвращать генерацию грамматически невалидных
последовательностей токенов (например, токена расширения сразу после токена
удержания) через маскирование невалидных кандидатов на каждом шаге.
### 3.6 Подсистема оценки
**ФТ-17.** Система должна предоставлять скрипт оценки, принимающий на вход
два чекпоинта (базовый и целевой) и отложенную выборку, и формирующий:
- Численные метрики перплексии для обеих моделей.
- Графики распределений по ключевым гармоническим признакам.
- Сгенерированные образцы для качественного сравнения.
**ФТ-18.** Графики распределений должны включать:
- Распределение типов качеств аккордов.
- Долю аккордов с расширениями.
- Долю аккордов с инверсиями.
- Распределение интервалов движения корня.
- Распределение наиболее частых пар «корень-корень» (биграммы).
Каждый график должен показывать baseline-распределение и target-распределение
на одной координатной плоскости с легендой.
---
## 4. Нефункциональные требования
### 4.1 Производительность
**НФТ-1.** Парсинг одного `.chord`-файла должен выполняться менее чем за
100 миллисекунд на стандартном персональном компьютере.
**НФТ-2.** Один проход обучения по тренировочной выборке (одна эпоха) на
полном McGill корпусе должен укладываться в 10 минут на CPU современного
ноутбука.
**НФТ-3.** Генерация одного периода должна занимать менее 10 секунд на CPU.
### 4.2 Корректность
**НФТ-4.** Парсер аккордовых символов должен корректно обрабатывать все
примеры, перечисленные в §4.6 спецификации формата.
**НФТ-5.** Round-trip эквивалентность (см. ФТ-6) должна подтверждаться
автоматизированными тестами для всех тестовых фикстур.
**НФТ-6.** Транспозиция должна быть точной: после транспозиции мажорного
периода в C major все аккорды должны находиться в правильных функциональных
отношениях с новой тоникой.
### 4.3 Воспроизводимость
**НФТ-7.** Все скрипты обучения, инференса и оценки должны принимать параметр
случайного зерна и устанавливать его одновременно для PyTorch, NumPy и
стандартного модуля random.
**НФТ-8.** При фиксированном случайном зерне и идентичных входных данных
запуски обучения должны давать численно воспроизводимые результаты.
**НФТ-9.** Все эксперименты, упомянутые в итоговом отчёте, должны быть
воспроизводимы посредством запуска документированных команд.
### 4.4 Надёжность работы с данными
**НФТ-10.** Невалидные или непарсимые аккордовые символы должны вызывать
явные ошибки с информативным сообщением. Тихая подмена неизвестных символов
на «ближайшие» категорически запрещена: это приводит к молчаливому
повреждению обучающего корпуса.
**НФТ-11.** Файлы из отложенной выборки не должны использоваться на этапах
тренировки или валидации. Любой скрипт подготовки данных, при обнаружении
файла в `data/holdout/`, должен направлять его в отдельную holdout-выборку.
### 4.5 Сопровождаемость
**НФТ-12.** Все публичные функции в модулях `src/` должны иметь аннотации
типов и краткие docstrings.
**НФТ-13.** Логика парсинга, токенизации и MIDI-экспорта должна покрываться
модульными тестами с использованием pytest.
**НФТ-14.** Спецификация формата `.chord` является контрактом между уровнем
человекочитаемых данных и уровнем обучения модели. Любые изменения формата
должны сопровождаться обновлением `docs/chord_format_spec.md` и инкрементом
номера версии спецификации.
### 4.6 Удобство использования
**НФТ-15.** Каждый CLI-скрипт должен поддерживать флаг `--help` с
информативным описанием параметров.
**НФТ-16.** Сообщения об ошибках должны содержать достаточно информации для
самостоятельного устранения проблемы пользователем: имя файла, номер строки,
характер нарушения, ожидаемое значение.
---
## 5. Критерии приёмки
Проект считается завершённым при выполнении всех нижеперечисленных условий.
### 5.1 Учебные критерии
| ID | Критерий |
| ---- | ----------------------------------------------------------------------------------------------------------- |
| УК-1 | Реализован полный цикл подготовки данных, обучения, инференса и оценки. |
| УК-2 | Имеется как минимум одна обученная модель, прошедшая стадии предобучения и дообучения. |
| УК-3 | Подготовлен итоговый отчёт, оформленный по стандартам ГОСТ для учебных работ. |
| УК-4 | Отчёт содержит количественное сравнение базовой и дообученной моделей. |
| УК-5 | Отчёт содержит качественные примеры сгенерированных периодов. |
| УК-6 | Все эксперименты, упомянутые в отчёте, воспроизводимы по командам, приведённым в README или в самом отчёте. |
### 5.2 Технические критерии
| ID | Критерий |
| ---- | --------------------------------------------------------------------------------------------------------------- |
| ТК-1 | Все автоматизированные тесты проходят. |
| ТК-2 | Round-trip эквивалентность парсера-токенизатора подтверждена на всех тестовых фикстурах. |
| ТК-3 | Транспозиция протестирована для мажорных и минорных периодов с разными исходными тональностями. |
| ТК-4 | Модель обучается до сходимости (валидационная потеря выходит на плато или снижается монотонно). |
| ТК-5 | Перплексия дообученной модели на отложенной выборке ниже перплексии базовой модели на той же выборке. |
| ТК-6 | На графиках распределений виден заметный сдвиг от baseline в сторону характеристик собственного корпуса автора. |
### 5.3 Прикладные критерии
| ID | Критерий |
| ---- | ------------------------------------------------------------------------------------------------------------------------------------ |
| ПК-1 | Автор может сгенерировать гармоническую последовательность по произвольным входным параметрам и воспроизвести её в DAW. |
| ПК-2 | Сгенерированные последовательности отличаются от случайного шума: соблюдается тональная стабильность, аккорды функционально связаны. |
| ПК-3 | На качественном уровне в нескольких из сгенерированных примеров автор слышит элементы собственного стиля. |
---
## 6. Намеренно выведенное за рамки
Перечисленные ниже возможности **не входят** в требования к текущей версии
проекта. Их реализация может рассматриваться как направления дальнейшего
развития после защиты курсовой работы.
| Возможность | Причина выведения |
| -------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| Генерация мелодической линии | Кратно увеличивает сложность задачи; не помещается в срок |
| Расположение голосов в аккорде (voicing) выше баса | Требует существенно большего датасета; ручная реализация в DAW проще |
| Ритмический паттерн внутри удержания аккорда | Требует моделирования времени с большим разрешением; не критично для задачи |
| Дообучение на корпусе японской поп-музыки | Запланировано как отдельный последующий эксперимент |
| Графический интерфейс | Не добавляет ценности с точки зрения учебных целей; занимает время |
| Прямая интеграция с REAPER | Обмен через MIDI-файлы достаточен и проще в реализации |
| Сравнение нескольких архитектур модели | Не помещается в срок; выбрана одна архитектура с обоснованием |
| Слепой listening-тест с привлечением слушателей | Не помещается в срок; используются качественные примеры |
| Обработка модуляций внутри одного периода | Решено разрезанием периодов по точке модуляции |
| Поддержка микротональных аккордов | Не встречается в целевом материале; округление до темперированного эквивалента |
| Поддержка полиаккордов | Редкое явление в целевом материале; запись через слэш-нотацию или ближайший single chord |
---
## 7. Сценарии использования
### 7.1 Сценарий У-1. Транскрипция собственной пьесы
**Действующее лицо:** автор-композитор.
**Предусловия:** в DAW-проекте имеется готовая пьеса с гармонической
структурой, доступной анализу. Установлена и настроена среда разработки.
**Основной поток:**
1. Автор прослушивает пьесу и определяет границы периодов.
2. Для каждого периода создаёт `.chord`-файл и заполняет шапку.
3. Транскрибирует гармонию по позициям, фиксируя инверсии и расширения.
4. Запускает валидатор формата для проверки корректности.
5. Экспортирует периоды в MIDI и прослушивает в DAW параллельно с оригиналом.
6. Корректирует транскрипцию в случае расхождений.
**Постусловия:** в `data/raw_user/` появились новые `.chord`-файлы,
прошедшие валидацию.
### 7.2 Сценарий У-2. Полный цикл обучения
**Действующее лицо:** автор-композитор.
**Предусловия:** подготовлен собственный корпус и сконвертирован публичный
корпус.
**Основной поток:**
1. Запуск скрипта подготовки данных для публичного корпуса.
2. Запуск скрипта подготовки данных для собственного корпуса.
3. Запуск скрипта предобучения, ожидание сходимости.
4. Запуск скрипта дообучения с инициализацией из чекпоинта предобучения.
5. Запуск скрипта оценки для сравнения базовой и дообученной моделей.
6. Анализ полученных графиков и метрик.
**Постусловия:** в `checkpoints/` сохранены обученные модели, в `reports/`
сформированы графики и численные метрики.
### 7.3 Сценарий У-3. Генерация гармонической идеи
**Действующее лицо:** автор-композитор в процессе работы над новой пьесой.
**Предусловия:** имеется обученная модель.
**Основной поток:**
1. Автор определяет желаемые параметры будущего периода: тональность,
функциональную роль, общий характер.
2. Запускает скрипт генерации с этими параметрами.
3. Получает `.chord`-файл и MIDI-файл результата.
4. Открывает MIDI-файл в DAW и прослушивает.
5. В случае удовлетворительного результата — переносит гармоническую
последовательность в свой композиторский проект.
6. В противном случае — повторяет генерацию с другим случайным зерном или
другими параметрами сэмплирования.
**Постусловия:** автор получает гармоническую идею в требуемом стилистическом
ключе.
### 7.4 Сценарий У-4. Продолжение начатой идеи
**Действующее лицо:** автор-композитор, у которого уже есть начало
гармонической последовательности.
**Предусловия:** имеется обученная модель и сформулированная гармоническая
затравка из нескольких аккордов.
**Основной поток:**
1. Автор формулирует затравку в виде строки аккордовых символов.
2. Запускает скрипт генерации с параметром `--prefix`.
3. Модель достраивает остаток периода с учётом затравки.
4. Получает MIDI и прослушивает.
**Постусловия:** автор получает варианты продолжения для своей гармонической
идеи.
---
## 8. История изменений
- **1.0** (2026-05-19) — первоначальная редакция документа.