# Архитектура системы 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 = + метатокены + опциональный prefix │ │ авторегрессионная генерация (top-p sampling) ▼ последовательность токенов до │ │ детокенизация ▼ 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]` — словарь токенов в порядке, описанном в спецификации формата (85 токенов). - Константа `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`-файлы загружаются в память при создании датасета. Это допустимо при текущем размере данных (тысячи периодов максимум) и существенно ускоряет обучение по сравнению с подгрузкой с диска. Паддинг выполняется специальным токеном `` с индексом 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. Останов при появлении `` или при достижении лимита токенов. После завершения генерации последовательность детокенизируется, получившийся период транспонируется из канонической тональности в целевую и возвращается вызывающему. ### 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 токенов | | Размер словаря | 85 | | Dropout | 0.1 | При необходимости конфигурация может быть пересмотрена в сторону уменьшения (если модель не сходится) или увеличения (если результаты явно недостаточны и есть запас времени на эксперимент). ### 4.3 Функция потерь и оптимизация Стандартная кросс-энтропия с игнорированием ``-токена. Оптимизатор — 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`. Словарь содержит 85 токенов против нескольких сотен в случае атомарной токенизации. **Последствия.** - Существенно меньший словарь, легче обучаемый на малых данных. - Модель видит общность между, например, всеми минорными септаккордами, а не учит их как 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__`, переключающего тонический центр в середине последовательности. **Что нужно сделать.** Расширить словарь токенов на 24 модуляционных токена. Дополнить парсер и токенизатор поддержкой inline-меток модуляции. Накопить достаточное число обучающих примеров с модуляциями (что проблематично при малом исходном корпусе). **Сложность.** Средняя, основное ограничение — данные. ### 8.7 Поддержка большего числа альтераций в аккорде **Описание.** Текущая версия поддерживает один слот расширения на аккорд. Альтерированные доминанты с несколькими альтерациями одновременно (`C7♯9♭13`) сворачиваются до одной альтерации. **Что нужно сделать.** Перейти от единственного `EXT_x` токена к множеству одновременных токенов расширений. Это требует пересмотра грамматики последовательности и формата представления одного аккорда (теперь его описание становится не четырёхтокеновым, а переменной длины). **Сложность.** Средняя, в основном проектная — требуется аккуратное обновление формата с инкрементом версии. --- ## 9. История изменений - **1.0** (2026-05-19) — первоначальная редакция документа.