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>
55 KiB
Архитектура системы hamori
Версия документа: 1.0 Дата: 2026-05-19
Документ описывает архитектуру проекта hamori — генератора гармонических периодов: высокоуровневую структуру, потоки данных, состав модулей, ключевые проектные решения и их обоснование, а также точки расширения.
Содержание
- Высокоуровневая архитектура
- Потоки данных
- Состав модулей
- Модель машинного обучения
- Конвейер обучения
- Конвейер инференса и оценки
- Ключевые проектные решения
- Точки расширения
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в dataclassChordTokens(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.
Ключевые соображения реализации. Авторегрессионная генерация выполняется по одному токену за раз. Для каждого шага:
- Прогон последовательности через модель, получение распределения над следующим токеном.
- Деление логитов на температуру.
- Применение nucleus sampling: оставляем минимальный по числу элементов набор кандидатов с накопленной вероятностью не менее top_p.
- Маскирование грамматически невалидных кандидатов (например, токена расширения сразу после токена удержания).
- Сэмплирование из оставшегося распределения.
- Останов при появлении
<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) — первоначальная редакция документа.