MORTM 3.2__tar.gz → 4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mortm-4.0/MORTM.egg-info/PKG-INFO +265 -0
- {mortm-3.2 → mortm-4.0}/MORTM.egg-info/SOURCES.txt +7 -3
- mortm-4.0/PKG-INFO +265 -0
- mortm-4.0/README.md +252 -0
- mortm-4.0/mortm/convert.py +858 -0
- mortm-4.0/mortm/custom_token.py +593 -0
- {mortm-3.2 → mortm-4.0}/mortm/de_convert.py +9 -8
- mortm-4.0/mortm/eval.py +155 -0
- {mortm-3.2 → mortm-4.0}/mortm/models/bertm.py +42 -17
- mortm-4.0/mortm/models/modules/attention.py +188 -0
- mortm-4.0/mortm/models/modules/audio_patch.py +44 -0
- mortm-4.0/mortm/models/modules/config.py +55 -0
- mortm-4.0/mortm/models/modules/layers.py +319 -0
- {mortm-3.2 → mortm-4.0}/mortm/models/mortm.py +41 -31
- mortm-4.0/mortm/models/v_mortm.py +65 -0
- mortm-4.0/mortm/train/config.py +36 -0
- {mortm-3.2 → mortm-4.0}/mortm/train/datasets.py +45 -4
- {mortm-3.2 → mortm-4.0}/mortm/train/epoch.py +5 -1
- {mortm-3.2 → mortm-4.0}/mortm/train/tokenizer.py +23 -5
- mortm-4.0/mortm/train/train.py +549 -0
- mortm-4.0/mortm/train/utils/__init__.py +0 -0
- mortm-4.0/mortm/train/utils/chord_midi.py +47 -0
- mortm-4.0/mortm/train/utils/loss.py +17 -0
- {mortm-3.2 → mortm-4.0}/setup.py +6 -4
- mortm-3.2/MORTM.egg-info/PKG-INFO +0 -24
- mortm-3.2/PKG-INFO +0 -24
- mortm-3.2/README.md +0 -3
- mortm-3.2/mortm/convert.py +0 -217
- mortm-3.2/mortm/custom_token.py +0 -329
- mortm-3.2/mortm/eval.py +0 -265
- mortm-3.2/mortm/generate.py +0 -37
- mortm-3.2/mortm/models/modules/attention.py +0 -669
- mortm-3.2/mortm/models/modules/config.py +0 -21
- mortm-3.2/mortm/models/modules/layers.py +0 -337
- mortm-3.2/mortm/train/re_train.py +0 -214
- mortm-3.2/mortm/train/train.py +0 -299
- {mortm-3.2 → mortm-4.0}/MORTM.egg-info/dependency_links.txt +0 -0
- {mortm-3.2 → mortm-4.0}/MORTM.egg-info/top_level.txt +0 -0
- {mortm-3.2 → mortm-4.0}/mortm/__init__.py +0 -0
- {mortm-3.2 → mortm-4.0}/mortm/constants.py +0 -0
- {mortm-3.2 → mortm-4.0}/mortm/gmail_messanger.py +0 -0
- {mortm-3.2 → mortm-4.0}/mortm/messager.py +0 -0
- {mortm-3.2 → mortm-4.0}/mortm/models/__init__.py +0 -0
- {mortm-3.2 → mortm-4.0}/mortm/models/modules/PositionalEncoding.py +0 -0
- {mortm-3.2 → mortm-4.0}/mortm/models/modules/__init__.py +0 -0
- {mortm-3.2 → mortm-4.0}/mortm/models/modules/progress.py +0 -0
- {mortm-3.2 → mortm-4.0}/mortm/re/RLDF.py +0 -0
- {mortm-3.2 → mortm-4.0}/mortm/re/__init__.py +0 -0
- {mortm-3.2 → mortm-4.0}/mortm/train/__init__.py +0 -0
- {mortm-3.2 → mortm-4.0}/mortm/train/noam.py +0 -0
- {mortm-3.2 → mortm-4.0}/setup.cfg +0 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: MORTM
|
|
3
|
+
Version: 4.0
|
|
4
|
+
Summary: 旋律生成、コード推定、マルチタスクな音楽生成を行うライブラリ
|
|
5
|
+
Home-page: https://github.com/Ayato964
|
|
6
|
+
Author: Nagoshi Takaaki
|
|
7
|
+
Author-email: nagoshi@kthrlab.jp
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.0
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# 🎵 MORTM: Metric-Oriented Rhythmic Transformer for Music Generation
|
|
15
|
+
|
|
16
|
+
[](https://opensource.org/licenses/MIT)
|
|
17
|
+
|
|
18
|
+
**MORTM (Metric-Oriented Rhythmic Transformer for Music Generation)** is a Transformer-based melody generation model that focuses on the **metric structure** of music. It generates musical sequences autoregressively, one bar at a time, while preserving rhythmic consistency. MORTM also includes `V_MORTM` for audio-based generation and `BERTM` for music classification tasks.
|
|
19
|
+
|
|
20
|
+
## ✨ Features
|
|
21
|
+
|
|
22
|
+
* **Bar-level Autoregressive Generation**: Normalizes each bar to 64 ticks and generates one bar at a time.
|
|
23
|
+
* **High-Quality Music Generation**: Uses a custom tokenizer to capture musical structure (pitch, duration, relative timing, bars), leading to coherent outputs.
|
|
24
|
+
* **Efficient Transformer Architecture**:
|
|
25
|
+
|
|
26
|
+
* **Decoder-Only (GPT-style)**: Optimized for autoregressive generation.
|
|
27
|
+
* **FlashAttention2 & ALiBi**: Memory-efficient, high-speed attention with excellent long-sequence generalization.
|
|
28
|
+
* **Mixture of Experts (MoE)**: Sparsely activated FFN layers for higher capacity.
|
|
29
|
+
* **Structured Tokenization**: Tokens for `Pitch`, `Duration`, `Position` and structural tokens like `<SME>`, `<TS>`, `<TE>`. Normalizes to 96 ticks per bar.
|
|
30
|
+
* **Multimodal (`V_MORTM`)**: Processes audio features (Mel spectrograms) directly.
|
|
31
|
+
* **Classification (`BERTM`)**: A BERT-like encoder for music classification tasks.
|
|
32
|
+
* **Versatile Applications**: Melody generation, improvisation assistance, education, human-AI co-creation, audio style transfer.
|
|
33
|
+
|
|
34
|
+
## 🚀 Why MORTM?
|
|
35
|
+
|
|
36
|
+
* **State-of-the-Art**: Combines FlashAttention2, MoE, and ALiBi.
|
|
37
|
+
* **Musical Understanding**: Custom tokenizer captures core musical elements.
|
|
38
|
+
* **Scalability**: Supports diverse styles and long sequences.
|
|
39
|
+
* **Audio Domain**: `V_MORTM` for richer audio-based generation.
|
|
40
|
+
* **Modular**: Easy prototyping and comparative experiments.
|
|
41
|
+
|
|
42
|
+
## 🛠️ Installation
|
|
43
|
+
|
|
44
|
+
### Prerequisites
|
|
45
|
+
|
|
46
|
+
* Python 3.8+
|
|
47
|
+
* NVIDIA GPU (for FlashAttention2)
|
|
48
|
+
* CUDA Toolkit (compatible with PyTorch)
|
|
49
|
+
|
|
50
|
+
### 1. Install PyTorch
|
|
51
|
+
|
|
52
|
+
Follow instructions at [pytorch.org](https://pytorch.org/get-started/locally/). Example:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 2. Install FlashAttention2
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pip install flash-attn --no-build-isolation
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 3. Install Other Dependencies
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pip install numpy einops pretty_midi midi2audio soundfile torchaudio PyYAML
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
* `midi2audio` requires FluidSynth and a soundfont (e.g., `.sf2`).
|
|
71
|
+
|
|
72
|
+
### 4. Optional: Gmail Notifications
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pip install google-api-python-client google-auth-httplib2 google-auth-oauthlib
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Requires OAuth2 setup (`client_secret.json`).
|
|
79
|
+
|
|
80
|
+
## ⚡ Quick Start
|
|
81
|
+
|
|
82
|
+
### Data Preparation
|
|
83
|
+
|
|
84
|
+
Convert MIDI to tokenized `.npz`:
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from mortm.train.tokenizer import Tokenizer, get_token_converter, TO_TOKEN
|
|
88
|
+
from mortm.convert import MIDI2Seq
|
|
89
|
+
|
|
90
|
+
tokenizer = Tokenizer(music_token=get_token_converter(TO_TOKEN))
|
|
91
|
+
converter = MIDI2Seq(tokenizer, "midi_dir", "your_midi.mid", program_list=[0], split_measure=12)
|
|
92
|
+
converter.convert()
|
|
93
|
+
converter.save("output_npz_dir")
|
|
94
|
+
|
|
95
|
+
# Save tokenizer vocabulary
|
|
96
|
+
tokenizer.save("vocab_output_dir")
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Inference
|
|
100
|
+
|
|
101
|
+
### MORTM: Melody Generation
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
import torch
|
|
105
|
+
import numpy as np
|
|
106
|
+
from mortm.models.mortm import MORTM, MORTMArgs
|
|
107
|
+
from mortm.train.tokenizer import Tokenizer, get_token_converter, TO_MUSIC
|
|
108
|
+
from mortm.de_convert import ct_token_to_midi
|
|
109
|
+
from mortm.models.modules.progress import _DefaultLearningProgress
|
|
110
|
+
|
|
111
|
+
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
|
112
|
+
tokenizer = Tokenizer(music_token=get_token_converter(TO_MUSIC), load_data="vocab_list.json")
|
|
113
|
+
args = MORTMArgs("configs/models/mortm/A.json")
|
|
114
|
+
model = MORTM(progress=_DefaultLearningProgress(), args=args)
|
|
115
|
+
model.load_state_dict(torch.load("trained_mortm.pth", map_location=DEVICE))
|
|
116
|
+
model.to(DEVICE).eval()
|
|
117
|
+
|
|
118
|
+
seed_ids = torch.tensor([tokenizer.get("<GEN>"), tokenizer.get("<TS>")], device=DEVICE)
|
|
119
|
+
with torch.no_grad():
|
|
120
|
+
_, full_seq = model.top_p_sampling_measure(seed_ids, p=0.95, max_measure=8, temperature=0.7)
|
|
121
|
+
|
|
122
|
+
ct_token_to_midi(tokenizer, full_seq, "generated_melody.mid", program=0, tempo=120)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### BERTM: Music Classification
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
import torch
|
|
129
|
+
import numpy as np
|
|
130
|
+
import torch.nn.functional as F
|
|
131
|
+
from mortm.models.bertm import BERTM, MORTMArgs as BERTMArgs
|
|
132
|
+
from mortm.train.tokenizer import Tokenizer, get_token_converter, TO_MUSIC
|
|
133
|
+
from mortm.models.modules.progress import _DefaultLearningProgress
|
|
134
|
+
|
|
135
|
+
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
|
136
|
+
tokenizer = Tokenizer(music_token=get_token_converter(TO_MUSIC), load_data="vocab_list.json")
|
|
137
|
+
args = BERTMArgs("configs/models/bertm/class_file.json")
|
|
138
|
+
model = BERTM(progress=_DefaultLearningProgress(), args=args)
|
|
139
|
+
model.load_state_dict(torch.load("trained_bertm.pth", map_location=DEVICE))
|
|
140
|
+
model.to(DEVICE).eval()
|
|
141
|
+
|
|
142
|
+
input_npz = np.load("input_music.npz")['array1']
|
|
143
|
+
input_ids = torch.tensor(input_npz, dtype=torch.long, device=DEVICE).unsqueeze(0)
|
|
144
|
+
with torch.no_grad():
|
|
145
|
+
logits = model(input_ids)
|
|
146
|
+
probs = F.softmax(logits, dim=-1)
|
|
147
|
+
pred = "Human" if probs.argmax() == 0 else "AI"
|
|
148
|
+
print(f"Prediction: {pred}, Probabilities: {probs.squeeze().tolist()}")
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Training
|
|
152
|
+
|
|
153
|
+
### Train MORTM
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
python train_mortm_example.py --model_config configs/models/mortm/A.json \
|
|
157
|
+
--train_config configs/train/pre_training.json \
|
|
158
|
+
--root_directory path/to/npz_dataset \
|
|
159
|
+
--save_directory out/models_mortm \
|
|
160
|
+
--version MyMORTM_v1
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Train V\_MORTM
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
python train_v_mortm_example.py --model_config configs/models/v_mortm/A.json \
|
|
167
|
+
--train_config configs/train/pre_training.json \
|
|
168
|
+
--root_directory path/to/wav_dataset \
|
|
169
|
+
--save_directory out/models_v_mortm \
|
|
170
|
+
--version MyV_MORTM_v1
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Train BERTM
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
python train_bertm_example.py --model_config configs/models/bertm/class_file.json \
|
|
177
|
+
--train_config configs/train/pre_training.json \
|
|
178
|
+
--human_dir path/to/human_npz \
|
|
179
|
+
--ai_dir path/to/ai_npz \
|
|
180
|
+
--save_directory out/models_bertm \
|
|
181
|
+
--version MyBERTM_v1
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Troubleshooting
|
|
185
|
+
|
|
186
|
+
* **load\_state\_dict errors**: Check config and map\_location.
|
|
187
|
+
* **Inference errors**: Ensure correct tensor shapes and vocab.
|
|
188
|
+
* **CUDA OOM**: Reduce batch size or use smaller model.
|
|
189
|
+
* **FlashAttention2 issues**: Verify CUDA and compiler compatibility.
|
|
190
|
+
|
|
191
|
+
## Token Format (Example)
|
|
192
|
+
|
|
193
|
+
```plaintext
|
|
194
|
+
<Gen> <TS>
|
|
195
|
+
Pitch=64 Duration=8 Position=0
|
|
196
|
+
Pitch=66 Duration=8 Position=8
|
|
197
|
+
...
|
|
198
|
+
<TE> <SME>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
* `Pitch`: MIDI note number (e.g., 64 = E4)
|
|
202
|
+
* `Duration`: Length in ticks (8 ticks = eighth note)
|
|
203
|
+
* `Position`: Start position within the bar (0–95)
|
|
204
|
+
* `<SME>`: End of bar
|
|
205
|
+
* `<TS>/<TE>`: Track start/end tokens
|
|
206
|
+
|
|
207
|
+
## Training & Generation Workflow
|
|
208
|
+
|
|
209
|
+
1. Convert MIDI data into normalized token sequences.
|
|
210
|
+
2. Input one bar of tokens to the decoder.
|
|
211
|
+
3. Autoregressively generate the next bar.
|
|
212
|
+
4. Evaluation Metrics:
|
|
213
|
+
|
|
214
|
+
* Does each bar sum to 64 ticks?
|
|
215
|
+
* Frequency of out-of-scale notes.
|
|
216
|
+
* Musicality and phrasing smoothness.
|
|
217
|
+
|
|
218
|
+
## Model Variants
|
|
219
|
+
|
|
220
|
+
Defined in JSON configs (`configs/models/...`). Example:
|
|
221
|
+
|
|
222
|
+
| Parameter | Value | Description |
|
|
223
|
+
| ---------------- | ----- | ------------------------ |
|
|
224
|
+
| d\_model | 512 | Embedding dimension |
|
|
225
|
+
| num\_heads | 8 | Attention heads |
|
|
226
|
+
| num\_layers | 12 | Decoder layers |
|
|
227
|
+
| dim\_feedforward | 2048 | FFN dimension |
|
|
228
|
+
| num\_experts | 16 | MoE experts |
|
|
229
|
+
| topk\_experts | 2 | Active experts per token |
|
|
230
|
+
| vocab\_size | ... | From vocab\_list.json |
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
| Model | Layers | Experts | Shared Experts | Embedding Dim | Heads |
|
|
234
|
+
|-----------|--------|---------|----------------|----------------|--------|
|
|
235
|
+
| MORTM-C | 12 | 6 | 1 | 512 | 8 |
|
|
236
|
+
| MORTM-B | 12 | 12 | 1 | 512 | 8 |
|
|
237
|
+
| MORTM-A | 12 | 16 | 1 | 512 | 8 |
|
|
238
|
+
| MORTM-S | 12 | 24 | 1 | 512 | 8 |
|
|
239
|
+
| MORTM-SS | 12 | 64 | 1 | 512 | 8 |
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
## 🛠️ Techniques
|
|
243
|
+
|
|
244
|
+
* **FlashAttention2**: Efficient exact attention.
|
|
245
|
+
* **ALiBi**: Linear biases for relative positions.
|
|
246
|
+
* **MoE**: Sparse mixture-of-experts.
|
|
247
|
+
* **Absolute PE**: Optional for phrase preservation.
|
|
248
|
+
|
|
249
|
+
## License
|
|
250
|
+
|
|
251
|
+
MIT License
|
|
252
|
+
|
|
253
|
+
## References
|
|
254
|
+
|
|
255
|
+
* Vaswani et al., "Attention is All You Need"
|
|
256
|
+
* Dao et al., "FlashAttention: Fast and Memory-Efficient Exact Attention"
|
|
257
|
+
* Press et al., "Train Short, Test Long: Attention with Linear Biases"
|
|
258
|
+
* Shazeer et al., "Outrageously Large Neural Networks: The Sparsely-Gated Mixture-of-Experts Layer"
|
|
259
|
+
* Huang et al., "Music Transformer"
|
|
260
|
+
|
|
261
|
+
## Author
|
|
262
|
+
|
|
263
|
+
Takaaki Nagoshi
|
|
264
|
+
Graduate School of Integrated Basic Sciences, Nihon University
|
|
265
|
+
[cs23033@g.nihon-u.ac.jp](mailto:cs23033@g.nihon-u.ac.jp)
|
|
@@ -10,24 +10,28 @@ mortm/convert.py
|
|
|
10
10
|
mortm/custom_token.py
|
|
11
11
|
mortm/de_convert.py
|
|
12
12
|
mortm/eval.py
|
|
13
|
-
mortm/generate.py
|
|
14
13
|
mortm/gmail_messanger.py
|
|
15
14
|
mortm/messager.py
|
|
16
15
|
mortm/models/__init__.py
|
|
17
16
|
mortm/models/bertm.py
|
|
18
17
|
mortm/models/mortm.py
|
|
18
|
+
mortm/models/v_mortm.py
|
|
19
19
|
mortm/models/modules/PositionalEncoding.py
|
|
20
20
|
mortm/models/modules/__init__.py
|
|
21
21
|
mortm/models/modules/attention.py
|
|
22
|
+
mortm/models/modules/audio_patch.py
|
|
22
23
|
mortm/models/modules/config.py
|
|
23
24
|
mortm/models/modules/layers.py
|
|
24
25
|
mortm/models/modules/progress.py
|
|
25
26
|
mortm/re/RLDF.py
|
|
26
27
|
mortm/re/__init__.py
|
|
27
28
|
mortm/train/__init__.py
|
|
29
|
+
mortm/train/config.py
|
|
28
30
|
mortm/train/datasets.py
|
|
29
31
|
mortm/train/epoch.py
|
|
30
32
|
mortm/train/noam.py
|
|
31
|
-
mortm/train/re_train.py
|
|
32
33
|
mortm/train/tokenizer.py
|
|
33
|
-
mortm/train/train.py
|
|
34
|
+
mortm/train/train.py
|
|
35
|
+
mortm/train/utils/__init__.py
|
|
36
|
+
mortm/train/utils/chord_midi.py
|
|
37
|
+
mortm/train/utils/loss.py
|
mortm-4.0/PKG-INFO
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: MORTM
|
|
3
|
+
Version: 4.0
|
|
4
|
+
Summary: 旋律生成、コード推定、マルチタスクな音楽生成を行うライブラリ
|
|
5
|
+
Home-page: https://github.com/Ayato964
|
|
6
|
+
Author: Nagoshi Takaaki
|
|
7
|
+
Author-email: nagoshi@kthrlab.jp
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.0
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# 🎵 MORTM: Metric-Oriented Rhythmic Transformer for Music Generation
|
|
15
|
+
|
|
16
|
+
[](https://opensource.org/licenses/MIT)
|
|
17
|
+
|
|
18
|
+
**MORTM (Metric-Oriented Rhythmic Transformer for Music Generation)** is a Transformer-based melody generation model that focuses on the **metric structure** of music. It generates musical sequences autoregressively, one bar at a time, while preserving rhythmic consistency. MORTM also includes `V_MORTM` for audio-based generation and `BERTM` for music classification tasks.
|
|
19
|
+
|
|
20
|
+
## ✨ Features
|
|
21
|
+
|
|
22
|
+
* **Bar-level Autoregressive Generation**: Normalizes each bar to 64 ticks and generates one bar at a time.
|
|
23
|
+
* **High-Quality Music Generation**: Uses a custom tokenizer to capture musical structure (pitch, duration, relative timing, bars), leading to coherent outputs.
|
|
24
|
+
* **Efficient Transformer Architecture**:
|
|
25
|
+
|
|
26
|
+
* **Decoder-Only (GPT-style)**: Optimized for autoregressive generation.
|
|
27
|
+
* **FlashAttention2 & ALiBi**: Memory-efficient, high-speed attention with excellent long-sequence generalization.
|
|
28
|
+
* **Mixture of Experts (MoE)**: Sparsely activated FFN layers for higher capacity.
|
|
29
|
+
* **Structured Tokenization**: Tokens for `Pitch`, `Duration`, `Position` and structural tokens like `<SME>`, `<TS>`, `<TE>`. Normalizes to 96 ticks per bar.
|
|
30
|
+
* **Multimodal (`V_MORTM`)**: Processes audio features (Mel spectrograms) directly.
|
|
31
|
+
* **Classification (`BERTM`)**: A BERT-like encoder for music classification tasks.
|
|
32
|
+
* **Versatile Applications**: Melody generation, improvisation assistance, education, human-AI co-creation, audio style transfer.
|
|
33
|
+
|
|
34
|
+
## 🚀 Why MORTM?
|
|
35
|
+
|
|
36
|
+
* **State-of-the-Art**: Combines FlashAttention2, MoE, and ALiBi.
|
|
37
|
+
* **Musical Understanding**: Custom tokenizer captures core musical elements.
|
|
38
|
+
* **Scalability**: Supports diverse styles and long sequences.
|
|
39
|
+
* **Audio Domain**: `V_MORTM` for richer audio-based generation.
|
|
40
|
+
* **Modular**: Easy prototyping and comparative experiments.
|
|
41
|
+
|
|
42
|
+
## 🛠️ Installation
|
|
43
|
+
|
|
44
|
+
### Prerequisites
|
|
45
|
+
|
|
46
|
+
* Python 3.8+
|
|
47
|
+
* NVIDIA GPU (for FlashAttention2)
|
|
48
|
+
* CUDA Toolkit (compatible with PyTorch)
|
|
49
|
+
|
|
50
|
+
### 1. Install PyTorch
|
|
51
|
+
|
|
52
|
+
Follow instructions at [pytorch.org](https://pytorch.org/get-started/locally/). Example:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 2. Install FlashAttention2
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pip install flash-attn --no-build-isolation
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 3. Install Other Dependencies
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pip install numpy einops pretty_midi midi2audio soundfile torchaudio PyYAML
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
* `midi2audio` requires FluidSynth and a soundfont (e.g., `.sf2`).
|
|
71
|
+
|
|
72
|
+
### 4. Optional: Gmail Notifications
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pip install google-api-python-client google-auth-httplib2 google-auth-oauthlib
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Requires OAuth2 setup (`client_secret.json`).
|
|
79
|
+
|
|
80
|
+
## ⚡ Quick Start
|
|
81
|
+
|
|
82
|
+
### Data Preparation
|
|
83
|
+
|
|
84
|
+
Convert MIDI to tokenized `.npz`:
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from mortm.train.tokenizer import Tokenizer, get_token_converter, TO_TOKEN
|
|
88
|
+
from mortm.convert import MIDI2Seq
|
|
89
|
+
|
|
90
|
+
tokenizer = Tokenizer(music_token=get_token_converter(TO_TOKEN))
|
|
91
|
+
converter = MIDI2Seq(tokenizer, "midi_dir", "your_midi.mid", program_list=[0], split_measure=12)
|
|
92
|
+
converter.convert()
|
|
93
|
+
converter.save("output_npz_dir")
|
|
94
|
+
|
|
95
|
+
# Save tokenizer vocabulary
|
|
96
|
+
tokenizer.save("vocab_output_dir")
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Inference
|
|
100
|
+
|
|
101
|
+
### MORTM: Melody Generation
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
import torch
|
|
105
|
+
import numpy as np
|
|
106
|
+
from mortm.models.mortm import MORTM, MORTMArgs
|
|
107
|
+
from mortm.train.tokenizer import Tokenizer, get_token_converter, TO_MUSIC
|
|
108
|
+
from mortm.de_convert import ct_token_to_midi
|
|
109
|
+
from mortm.models.modules.progress import _DefaultLearningProgress
|
|
110
|
+
|
|
111
|
+
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
|
112
|
+
tokenizer = Tokenizer(music_token=get_token_converter(TO_MUSIC), load_data="vocab_list.json")
|
|
113
|
+
args = MORTMArgs("configs/models/mortm/A.json")
|
|
114
|
+
model = MORTM(progress=_DefaultLearningProgress(), args=args)
|
|
115
|
+
model.load_state_dict(torch.load("trained_mortm.pth", map_location=DEVICE))
|
|
116
|
+
model.to(DEVICE).eval()
|
|
117
|
+
|
|
118
|
+
seed_ids = torch.tensor([tokenizer.get("<GEN>"), tokenizer.get("<TS>")], device=DEVICE)
|
|
119
|
+
with torch.no_grad():
|
|
120
|
+
_, full_seq = model.top_p_sampling_measure(seed_ids, p=0.95, max_measure=8, temperature=0.7)
|
|
121
|
+
|
|
122
|
+
ct_token_to_midi(tokenizer, full_seq, "generated_melody.mid", program=0, tempo=120)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### BERTM: Music Classification
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
import torch
|
|
129
|
+
import numpy as np
|
|
130
|
+
import torch.nn.functional as F
|
|
131
|
+
from mortm.models.bertm import BERTM, MORTMArgs as BERTMArgs
|
|
132
|
+
from mortm.train.tokenizer import Tokenizer, get_token_converter, TO_MUSIC
|
|
133
|
+
from mortm.models.modules.progress import _DefaultLearningProgress
|
|
134
|
+
|
|
135
|
+
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
|
136
|
+
tokenizer = Tokenizer(music_token=get_token_converter(TO_MUSIC), load_data="vocab_list.json")
|
|
137
|
+
args = BERTMArgs("configs/models/bertm/class_file.json")
|
|
138
|
+
model = BERTM(progress=_DefaultLearningProgress(), args=args)
|
|
139
|
+
model.load_state_dict(torch.load("trained_bertm.pth", map_location=DEVICE))
|
|
140
|
+
model.to(DEVICE).eval()
|
|
141
|
+
|
|
142
|
+
input_npz = np.load("input_music.npz")['array1']
|
|
143
|
+
input_ids = torch.tensor(input_npz, dtype=torch.long, device=DEVICE).unsqueeze(0)
|
|
144
|
+
with torch.no_grad():
|
|
145
|
+
logits = model(input_ids)
|
|
146
|
+
probs = F.softmax(logits, dim=-1)
|
|
147
|
+
pred = "Human" if probs.argmax() == 0 else "AI"
|
|
148
|
+
print(f"Prediction: {pred}, Probabilities: {probs.squeeze().tolist()}")
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Training
|
|
152
|
+
|
|
153
|
+
### Train MORTM
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
python train_mortm_example.py --model_config configs/models/mortm/A.json \
|
|
157
|
+
--train_config configs/train/pre_training.json \
|
|
158
|
+
--root_directory path/to/npz_dataset \
|
|
159
|
+
--save_directory out/models_mortm \
|
|
160
|
+
--version MyMORTM_v1
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Train V\_MORTM
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
python train_v_mortm_example.py --model_config configs/models/v_mortm/A.json \
|
|
167
|
+
--train_config configs/train/pre_training.json \
|
|
168
|
+
--root_directory path/to/wav_dataset \
|
|
169
|
+
--save_directory out/models_v_mortm \
|
|
170
|
+
--version MyV_MORTM_v1
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Train BERTM
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
python train_bertm_example.py --model_config configs/models/bertm/class_file.json \
|
|
177
|
+
--train_config configs/train/pre_training.json \
|
|
178
|
+
--human_dir path/to/human_npz \
|
|
179
|
+
--ai_dir path/to/ai_npz \
|
|
180
|
+
--save_directory out/models_bertm \
|
|
181
|
+
--version MyBERTM_v1
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Troubleshooting
|
|
185
|
+
|
|
186
|
+
* **load\_state\_dict errors**: Check config and map\_location.
|
|
187
|
+
* **Inference errors**: Ensure correct tensor shapes and vocab.
|
|
188
|
+
* **CUDA OOM**: Reduce batch size or use smaller model.
|
|
189
|
+
* **FlashAttention2 issues**: Verify CUDA and compiler compatibility.
|
|
190
|
+
|
|
191
|
+
## Token Format (Example)
|
|
192
|
+
|
|
193
|
+
```plaintext
|
|
194
|
+
<Gen> <TS>
|
|
195
|
+
Pitch=64 Duration=8 Position=0
|
|
196
|
+
Pitch=66 Duration=8 Position=8
|
|
197
|
+
...
|
|
198
|
+
<TE> <SME>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
* `Pitch`: MIDI note number (e.g., 64 = E4)
|
|
202
|
+
* `Duration`: Length in ticks (8 ticks = eighth note)
|
|
203
|
+
* `Position`: Start position within the bar (0–95)
|
|
204
|
+
* `<SME>`: End of bar
|
|
205
|
+
* `<TS>/<TE>`: Track start/end tokens
|
|
206
|
+
|
|
207
|
+
## Training & Generation Workflow
|
|
208
|
+
|
|
209
|
+
1. Convert MIDI data into normalized token sequences.
|
|
210
|
+
2. Input one bar of tokens to the decoder.
|
|
211
|
+
3. Autoregressively generate the next bar.
|
|
212
|
+
4. Evaluation Metrics:
|
|
213
|
+
|
|
214
|
+
* Does each bar sum to 64 ticks?
|
|
215
|
+
* Frequency of out-of-scale notes.
|
|
216
|
+
* Musicality and phrasing smoothness.
|
|
217
|
+
|
|
218
|
+
## Model Variants
|
|
219
|
+
|
|
220
|
+
Defined in JSON configs (`configs/models/...`). Example:
|
|
221
|
+
|
|
222
|
+
| Parameter | Value | Description |
|
|
223
|
+
| ---------------- | ----- | ------------------------ |
|
|
224
|
+
| d\_model | 512 | Embedding dimension |
|
|
225
|
+
| num\_heads | 8 | Attention heads |
|
|
226
|
+
| num\_layers | 12 | Decoder layers |
|
|
227
|
+
| dim\_feedforward | 2048 | FFN dimension |
|
|
228
|
+
| num\_experts | 16 | MoE experts |
|
|
229
|
+
| topk\_experts | 2 | Active experts per token |
|
|
230
|
+
| vocab\_size | ... | From vocab\_list.json |
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
| Model | Layers | Experts | Shared Experts | Embedding Dim | Heads |
|
|
234
|
+
|-----------|--------|---------|----------------|----------------|--------|
|
|
235
|
+
| MORTM-C | 12 | 6 | 1 | 512 | 8 |
|
|
236
|
+
| MORTM-B | 12 | 12 | 1 | 512 | 8 |
|
|
237
|
+
| MORTM-A | 12 | 16 | 1 | 512 | 8 |
|
|
238
|
+
| MORTM-S | 12 | 24 | 1 | 512 | 8 |
|
|
239
|
+
| MORTM-SS | 12 | 64 | 1 | 512 | 8 |
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
## 🛠️ Techniques
|
|
243
|
+
|
|
244
|
+
* **FlashAttention2**: Efficient exact attention.
|
|
245
|
+
* **ALiBi**: Linear biases for relative positions.
|
|
246
|
+
* **MoE**: Sparse mixture-of-experts.
|
|
247
|
+
* **Absolute PE**: Optional for phrase preservation.
|
|
248
|
+
|
|
249
|
+
## License
|
|
250
|
+
|
|
251
|
+
MIT License
|
|
252
|
+
|
|
253
|
+
## References
|
|
254
|
+
|
|
255
|
+
* Vaswani et al., "Attention is All You Need"
|
|
256
|
+
* Dao et al., "FlashAttention: Fast and Memory-Efficient Exact Attention"
|
|
257
|
+
* Press et al., "Train Short, Test Long: Attention with Linear Biases"
|
|
258
|
+
* Shazeer et al., "Outrageously Large Neural Networks: The Sparsely-Gated Mixture-of-Experts Layer"
|
|
259
|
+
* Huang et al., "Music Transformer"
|
|
260
|
+
|
|
261
|
+
## Author
|
|
262
|
+
|
|
263
|
+
Takaaki Nagoshi
|
|
264
|
+
Graduate School of Integrated Basic Sciences, Nihon University
|
|
265
|
+
[cs23033@g.nihon-u.ac.jp](mailto:cs23033@g.nihon-u.ac.jp)
|