Table of Contents
- To run the experiment
- Configuration Files (
configs/) - Dataset (
data/midis/) - Corpus Structure (
data/corpora/) - Multinote BPE (
bpe/) - Model (
models/) - Codes (
util/) - Tool and Experiment Scripts
Create environment with conda:
conda env create --name {ENV_NAME} --file environment.ymlYou may need to clear cache first by pip cache purge and conda clean --all.
Make you own copy of config files (e.g.: configs/model/my_model_setting.sh) if you want to make some changes to the settings.
The config files are placed in configs/corpus, configs/bpe and configs/model.
Run ./pipeline.sh {corpus_config} {bpe_config} {model_config} to do everything from pre-processing to model training at once.
You can add --use-existed at the end of the command to tell pipeline.sh to just use the existing data.
You can recreate our experiment by running the scripts in experiment_script.
./experiment_script/data_preproc_and_bpe.sh
./experiment_script/apply_learned_contour_to_other.sh
./experiment_script/full_model_and_ablation.sh snd --full --ablation
./experiment_script/full_model_and_ablation.sh lmd_full --full --ablation(Optional 12-layer Linear Transformer model trained on LMD)
ONLY_EVAL_UNCOND=true ./pipeline.sh lmd_full ours_sample1.0 linear_mid --use-existed-
Files in
configs/corpusset parameters formidi_to_corpus.pyandmake_arrays.py- Vocabulary parameters:
TPQ: ticks per quarter note / time units per quarter noteMAX_TRACK_NUMBERMAX_DURATIONVELOCITY_STEP: quantize velocity value to(VELOCITY_STEP * 1, VELOCITY_STEP * 2, ... VELOCITY_STEP * k)wherek = 127 // VELOCITY_STEPCONTINUING_NOTE: use continuing note or notTEMPO_MIN,TEMPO_MAX,TEMPO_STEP
- Dataset processing setting
MIDI_WORKER_NUMBERMIDI_DIR_PATH: the path to dataset directoryDATA_NAMETEST_PATHS_FILE,VALID_PATHS_FILE: point to a file inconfigs/split
- Vocabulary parameters:
-
Files in
configs/bpeset parameters forbpe/mnbpe(implementation of Multi-note BPE algorithm).BPE_ITER_NUM: number of iteration / size of vocabularyADJACENCY: name of the adjacency; can be "ours" or "mulpi"MIN_SCORE: early-stop if the score of best contour (ie: its frequency) is less than itSAMPLE_RATE: track sampling rateBPE_LOG: output log or notBPE_WORKER_NUMBER
-
Files in
configs/modelset parameters fortrain.pyand the config file name underconfigs/evalto be used byevaluate_model.sh.SEED: random seed in training process- Dataset parameters
MAX_SEQ_LENGTH: max sequence length to feed into modelVIRTUAL_PIECE_STEP_RATIO: if > 0, split over-length pieces into multiple virtual piecesFLATTEN_VIRTUAL_PIECES: if true, all virtual pieces has a index number. Otherwise, virtual pieces within same real piece shares the same index numberPERMUTE_MPS: whether or not the dataset should permute all the maximal permutable subarrays as data augmentationPERMUTE_TRACK_NUMBER: Permute all the track numbers relative to the instruments as data augmentationPITCH_AUGMENTATION_RANGE
- Model parameter
USE_LINEAR_ATTENTIONLAYERS_NUMBERATTN_HEADS_NUMBEREMBEDDING_DIMNOT_USE_MPS_NUMBER
- Training parameter
BATCH_SIZEMAX_UPDATES: number of updates before training stopVALIDATION_INTERVAL: number of update before each validationMAX_GRAD_NORM- Learning rate schedule (linear warmup and then decay to end ratio) parameters
LEARNING_RATE_PEAKLEARNING_RATE_WARMUP_UPDATESLEARNING_RATE_DECAY_END_UPDATESLEARNING_RATE_DECAY_END_RATIO
EARLY_STOP: number of non-improved validation before early
- Others
USE_DEVICEEVAL_CONFIG_NAME: point to a file inconfigs/eval
-
Files in
configs/splitcontain lists of paths, relative to each dataset root, of midi files to be used as test set and validation set of the datasets. Their path are referenced by variableTEST_PATHS_FILEandVALID_PATHS_FILEin files ofconfigs/corpus. -
Files in
configs/evalstore parameters forevaluate_model.sh.SEED: random seed in evaluation/generation process- Generation setting
EVAL_SAMPLE_NUMBEREVAL_WORKER_NUMBERPRIMER_MEASURE_LENGTH: number of measure for primer-continuation generation taskSAMPLE_FUNCTION: can be "none", "top-p", "top-k"SAMPLE_THRESHOLDSOFTMAX_TEMPERATURE
- Evaluation setting
EVAL_MIDI_TO_PIECE_PARAS_FILE: the vocabulary parameter to quantize MIDI files when evaluating them
The datasets we used, SymphonyNet_Dataset and lmd_full, are expected to be found under data/midis. However, the path midi_to_corpus.py would be looking is the MIDI_DIR_PATH variables set in the the corpus configuration file. So it could be in any place you want. Just set the path right.
Corpora are located at data/corpora/. A complete "corpus" is directory containing at least 5 files in the following list.
-
corpus: A text file. Each\n-separated line is a text representation of a midi file. This is the "main form" of the representation. Created bymidi_to_corpus.py. -
paras: A yaml file that contains parameters of pre-processing used bymidi_to_corpus.py. Created bymidi_to_corpus.py. -
pathlist: A text file. Each\n-separated line is the path, relative to project root, of midi file corresponding to the text representation incorpus. Created bymidi_to_corpus.py.- Note that a corpus include all processable, uncorrupted midi file, including the test and validation files. The split of test and validation happens at training and evaluating stage.
-
vocabs.json: The vocabulary to be used by the model. The format is defined inutil/vocabs.py. Created bymake_arrays.py. -
arrays.npz: A zip file of numpy arrays in.npyformat. Can be accessed bynumpy.load()and it will return an instance ofNpzFileclass. This is the "final form" of the representation (i.e. include pre-computed MPS order positio numbers) that would be used to train model. Created bymake_arrays.py.
Other possible files and directories are:
-
stats/: A directoy that contains statistics about the corpus. Some figures outputed bymake_arrays.pyand byplot_bpe_log.pywould be end up here. -
contour_vocab: A text file created bybpe/mnbpe. If exist, it will be read bymake_arrays.pyto help createvocabs.json. -
arrays/: A temporary directory for placing the.npyfiles before they are zipped. -
make_array_debug.txt: A text file that shows array content of the first piece in the corpus. Created bymake_arrays.py.
Stuffs about Multi-note BPE are all in bpe/.
Source codes:
-
classes.cppandclasses.hpp: Define class of corpus, multi-note, rel-note, etc. And I/O functions. -
functions.cppandfunctions.hpp: Other functions and algorithms. -
mnbpe.cpp: main algorithm
They should compile to bpe/mnbpe with make -C bpe all:
Usage:
mnbpe [--log] [--worker-number <number>] [--apply <contour-vocab-path>] [--adj {"ours"|"mulpi"}] [--sampling-rate <rate>] [--min-score <score>] <in-corpus-dir-path> <out-corpus-dir-path> [<iteration-number>]
- If
--applyis set, the algorithm is in "apply mode". - Default Iteration number is the maximum acceptable size (66532).
- If the size of applying contour vocab is greater than the iteration number, only the first [iteration number] contours are applied.
-
Models are created by
train.py. -
Learning rate schedule is hard-coded warmup and linear decay.
-
acceleratefrom Huggingface when flag set for distributed training- in our config file, we use 4 devices
-
A completed trained model is stored at
models/{DATE_AND_FULL_CONFIG_NAME}/best_model.ptas a "pickled" python object that would be saved and loaded bytorch.save()andtorch.load(). -
Two directories are under
models/{DATE_AND_FULL_CONFIG_NAME}/ckpt/is where checkpoint model and generated sample would be placedeval_samples/is where the evaluation samples generated bygenerate_with_model.pycalled inevaluate_model.shwould be placed.
-
A file
models/{DATE_AND_FULL_CONFIG_NAME}/test_pathscontaining all paths to the test files would be created when runningevaluate_model.sh.
-
A "midi" means a
miditoolkit.MidiFileinstance. -
A "piece" means a string of text representation of midi file, without tailing
\n. -
A "text-list" means a list of strings obtained from
piece.split(' ')or can be turned into a "piece" after' '.join(text_list). -
An "array" means a 2-d numpy array that encoded a piece with respect to a vocabulary set.
-
argparse_helper.py- Misc. helper functions for argparse module.
-
arrays.py- Define the array form of the representation.
- Contain text-list-to-array and array-to-text-list functions.
-
corpus.py- Define corpus directory structure.
- Define corpus reader class
-
dataset.py- Define
MidiDatasetclass and the collate function.
- Define
-
evaluation.py- Contain functions for features computation and preparing data for features computation.
- Contain piece-to-feature and midi-to-feature functions.
- Contain funtion for aggregating features from all midis.
-
generation.py- Contain functions for generating using model.
-
midi.py- Contain the midi-to-piece and piece-to-midi functions.
-
model.py- Define
MyMidiTransformerclass, inherit fromtorch.nn.Module. - Define the loss functions for the model.
- Define
-
token.py- Define representation tokens and their "main form" (text representation).
- Contain some hard-coded configurations in midi preprocessing.
-
vocabs.py- Define
Vocabsclass that record the vocabulary set, vocabulary building configurations and midi preprocessing parameters. - Contain the build-vocabulary function.
- Define
-
extract.py: Used for debugging. Extract piece(s) from the given corpus directory into text representation(s), midi file(s), or piano-roll graph(s) in png. -
generate_with_models.py: Use model to generate midi files, with or without primer(s). -
get_eval_features_of_midis.py: Do as per its name. It will get midi files in a directory. Output results as a JSON fileeval_features.jsonat the root of the directory. -
make_arrays.py: Generatevocabs.jsonandarrays.npzfromcorpusandcontour_vocabif it exists. -
midi_to_corpus.py: Pre-process midi files into a "corpus". The parameter would be stored inparas. It createscorpus,paras, andpathlistin the corpus directory. -
plot_bpe_log.py: Make figures to visualize the data in the log files that contains the loggings of Multi-note BPE program. -
print_dataset.py: Used for debugging. Print out the results of dataset__getitem__and other related things. -
train.py: Train a model from a corpus. -
verify_corpus_equality.py: To make sure two corpus are representing the same list of midi files.
-
evaluate_model.sh- Read a file in
config/evalfor its arguments. - Get evaluation features of the dataset's
TEST_PATHS_FILEfiles usingget_eval_features_of_midis.py. - Get evaluation features of the unconditional, instrument-conditioned, and primer-continution generation result of the model using the combination of
generate_with_models.pyandget_eval_features_of_midis.py.
- Read a file in
-
experiment_scripts/: Pre-programmed experiment execution scriptapply_learned_contours_to_other.shdata_preproc_and_bpes.shfull_model_and_ablation.sh
-
test_scripts/: Likeexperiment_scripts/, but with test data and settings. These test scripts only see if everything runs on CPU and does not check the correctness of the result.test_apply_learned_contours.shtest_pipelines.sh
-
pipeline.sh:- Pre-process midi files into a corpus with
midi_to_corpus.py. - If
DO_BPEis "true", then runbpe/mnbpeto create a new merged corpus. After it is done, runverify_corpus_equality.pyto make sure there are no errors and runplot_bpe_log.pyto visualize the loggings. - Make arrays file and vocabs file of the corpus with
make_arrays.py. - Train a model on the corpus with
train.py. - Get evaluation features of training dataset the model generated midi files with
evaluate_model.sh.
- Pre-process midi files into a corpus with