├── .github
└── FUNDING.yml
├── LICENSE
├── MUSIC_INT_EVAL_DATASET.zip
├── README.md
├── Super Chamber Piano MIDI Sample.mid
├── Super Chamber Piano Only Notewise DataSet.zip
├── Super Chamber Piano Screenshot 1.png
├── Super Chamber Piano Screenshot 2.png
├── Super Chamber Piano Violin Notewise DataSet.zip
├── Super Chamber Piano WAV Sample.wav
├── Super-Piano-2-Monster-Samples-128-MIDIs-16k-long.zip
├── SuperPiano.ipynb
├── SuperPiano5_(Reformer_TPU).ipynb
├── Super_Chamber_Piano.ipynb
├── Super_Piano_2.ipynb
├── Super_Piano_3.ipynb
├── Super_Piano_3_Alt.ipynb
├── Super_Piano_3_Alt_2.ipynb
├── Super_Piano_4.ipynb
├── Super_Piano_6_Performer_GPU.ipynb
├── [TMIDI]_Super_Piano_3.ipynb
├── trained_model.h5
├── trained_model_jazz.h5
└── trained_model_piano.h5
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: ['https://paypal.me/AleksandrSigalov'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright 2021 Project Los Angeles / Tegridy Code
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/MUSIC_INT_EVAL_DATASET.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asigalov61/SuperPiano/83bfaccf50dcbc53349a389b60c37205b9d38162/MUSIC_INT_EVAL_DATASET.zip
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Super Piano
2 | ## SOTA Music AI Implementations Repo
3 | ### Built on Google XLNet/Transformer-XL SOTA AI Architecture)
4 |
5 | 
6 |
7 | Absolutely fantastic SOTA Google Colab (Jupyter) Notebooks to easily and quickly train a SOTA Music AI model and for generating music with Transformer technology (Google XLNet/Transformer-XL)
8 |
9 | Huge thanks goes to creators of the original repos/code that made these amazing Notebooks possible :) Thank you very much and the credit is all yours :)
10 |
11 | ## Description of each Super Piano Colab
12 |
13 | ### [THE BEST] Super Chamber Piano (Non-Transformer, pure LSTM, go figure :)
14 |
15 | Absolutely fantastic implementation of Chamber Piano that is capable of playing two instruments at once (Piano and Violin). Plays incredibly well and is capable of smooth continuations. Works well with Jazz as well. Check out screenshots, pre-trained model, and the dataset.
16 |
17 | Enjoy :)
18 |
19 | ### 1) Super Piano Original
20 |
21 | This All-In-One Composition Piano Colab/Model that is capable of either generating a perfomance or a pretty decent continuation of your own composition (Custom MIDI continuation option).
22 |
23 | Recommended for every purpose as it can handle any Piano composition task.
24 |
25 | It also uses block continuation schema, meaning that you can continue your composition to any desired length and you have full control over each continuation block (size, temp, etc).
26 |
27 | Most capable of my Super Piano Music AI models :)
28 |
29 | A better pre-trained model for this Piano will be coming very soon.
30 |
31 | ### 2) Super Piano 2
32 |
33 | This is by far the most capable of my Performance Super Pianos. Capable of super fast piano perfomances generation (any lenghs, any number of perfomances/batches).
34 |
35 | This version also has a histogram-based control option that produces very nice results.
36 |
37 | Does not work well with MAESTRO DataSet so please use provided Super Piano 2 MIDIs DataSet or use your own.
38 |
39 | Recommended use: Batch/Monster Perfomance generation based on a Histogram primer key. See instructions at the Generation Section in Colab where I provide examples.
40 |
41 | ### 3) Super Piano 3 [DOES NOT PLAY WELL DUE TO PROBLEMS WITH MIDI PROCESSOR and with some other stuff]
42 |
43 | SOTA Perfomance Colab/Model.
44 |
45 | This Piano also pretty much a very close copy (or rather a reproduction) of the Google Piano Trainsformer Paper/Model/Colab. Definitely check it out so that you can compare the output and reproducability with my implementation.
46 |
47 | Custom MIDI options also present but since it is a Performance model, it is not really designed to be controled or influenced.
48 |
49 | ### 4) Super Piano 4
50 |
51 | Fully Multi-instrumental LSTM Colab based on Google Transformer-XL architecture. Works well. Check it out.
52 |
53 | ## Some stats:
54 |
55 | Architecture Google XLNet/Transformer-XL (FastAI/PyTorch)
56 |
57 | You are welcome to train original models further or fine-tune them with your (smaller) MIDI dataset.
58 |
59 | Thank you and enjoy these amazing Music AI Notebooks :)
60 |
61 | Alex
62 | 
63 |
64 | [](https://github.com/anuraghazra/github-readme-stats)
65 |
--------------------------------------------------------------------------------
/Super Chamber Piano MIDI Sample.mid:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asigalov61/SuperPiano/83bfaccf50dcbc53349a389b60c37205b9d38162/Super Chamber Piano MIDI Sample.mid
--------------------------------------------------------------------------------
/Super Chamber Piano Only Notewise DataSet.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asigalov61/SuperPiano/83bfaccf50dcbc53349a389b60c37205b9d38162/Super Chamber Piano Only Notewise DataSet.zip
--------------------------------------------------------------------------------
/Super Chamber Piano Screenshot 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asigalov61/SuperPiano/83bfaccf50dcbc53349a389b60c37205b9d38162/Super Chamber Piano Screenshot 1.png
--------------------------------------------------------------------------------
/Super Chamber Piano Screenshot 2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asigalov61/SuperPiano/83bfaccf50dcbc53349a389b60c37205b9d38162/Super Chamber Piano Screenshot 2.png
--------------------------------------------------------------------------------
/Super Chamber Piano Violin Notewise DataSet.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asigalov61/SuperPiano/83bfaccf50dcbc53349a389b60c37205b9d38162/Super Chamber Piano Violin Notewise DataSet.zip
--------------------------------------------------------------------------------
/Super Chamber Piano WAV Sample.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asigalov61/SuperPiano/83bfaccf50dcbc53349a389b60c37205b9d38162/Super Chamber Piano WAV Sample.wav
--------------------------------------------------------------------------------
/Super-Piano-2-Monster-Samples-128-MIDIs-16k-long.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asigalov61/SuperPiano/83bfaccf50dcbc53349a389b60c37205b9d38162/Super-Piano-2-Monster-Samples-128-MIDIs-16k-long.zip
--------------------------------------------------------------------------------
/SuperPiano.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "kernelspec": {
6 | "name": "python3",
7 | "display_name": "Python 3"
8 | },
9 | "language_info": {
10 | "codemirror_mode": {
11 | "name": "ipython",
12 | "version": 3
13 | },
14 | "file_extension": ".py",
15 | "mimetype": "text/x-python",
16 | "name": "python",
17 | "nbconvert_exporter": "python",
18 | "pygments_lexer": "ipython3",
19 | "version": "3.7.2"
20 | },
21 | "colab": {
22 | "name": "SuperPiano.ipynb",
23 | "provenance": [],
24 | "collapsed_sections": [],
25 | "toc_visible": true,
26 | "include_colab_link": true
27 | },
28 | "accelerator": "GPU"
29 | },
30 | "cells": [
31 | {
32 | "cell_type": "markdown",
33 | "metadata": {
34 | "id": "view-in-github",
35 | "colab_type": "text"
36 | },
37 | "source": [
38 | "
"
39 | ]
40 | },
41 | {
42 | "cell_type": "markdown",
43 | "metadata": {
44 | "id": "B15H9oWKZSA7",
45 | "colab_type": "text"
46 | },
47 | "source": [
48 | "# SUPER PIANO (XLNet Piano)"
49 | ]
50 | },
51 | {
52 | "cell_type": "markdown",
53 | "metadata": {
54 | "id": "WSDH5TNUZcex",
55 | "colab_type": "text"
56 | },
57 | "source": [
58 | "
\n",
59 | "\n",
60 | "Huge thanks goes to Andrew Shaw (bearpelican) for the MusicAutoBot repo/code that was used to create this notebook. This notebook is a fork of Andrew's notebook for MusicTransformer\n",
61 | "\n",
62 | "https://github.com/bearpelican\n",
63 | "\n",
64 | "https://github.com/bearpelican/musicautobot"
65 | ]
66 | },
67 | {
68 | "cell_type": "markdown",
69 | "metadata": {
70 | "id": "F3N-SRlpNtm7",
71 | "colab_type": "text"
72 | },
73 | "source": [
74 | "# SETUP THE ENVIRONMENT"
75 | ]
76 | },
77 | {
78 | "cell_type": "code",
79 | "metadata": {
80 | "id": "dzrRdTvlJdFd",
81 | "colab_type": "code",
82 | "cellView": "form",
83 | "colab": {}
84 | },
85 | "source": [
86 | "#@title Install all dependencies/clone repos/import modules\n",
87 | "!git clone https://github.com/asigalov61/musicautobot.git\n",
88 | "!nvidia-smi\n",
89 | "!apt install fluidsynth\n",
90 | "!gsutil -q -m cp gs://magentadata/soundfonts/Yamaha-C5-Salamander-JNv5.1.sf2 /content/musicautobot\n",
91 | "!pip install torch fastai music21 pebble fluidsynth midi2audio\n",
92 | "!pip install pretty_midi\n",
93 | "!pip install pypianoroll\n",
94 | "!pip install mir_eval\n",
95 | "\n",
96 | "import os\n",
97 | "os.chdir('musicautobot')\n",
98 | "from musicautobot.numpy_encode import *\n",
99 | "from musicautobot.utils.file_processing import process_all, process_file\n",
100 | "from musicautobot.config import *\n",
101 | "from musicautobot.music_transformer import *\n",
102 | "from musicautobot.numpy_encode import stream2npenc_parts\n",
103 | "from musicautobot.utils.midifile import *\n",
104 | "from fastai.text import *\n",
105 | "from midi2audio import FluidSynth\n",
106 | "from IPython.display import Audio\n",
107 | "# Colab cannot play music directly from music21 - must convert to .wav first\n",
108 | "def play_wav(stream):\n",
109 | " out_midi = stream.write('midi')\n",
110 | " out_wav = str(Path(out_midi).with_suffix('.wav'))\n",
111 | " FluidSynth(\"/content/musicautobot/Yamaha-C5-Salamander-JNv5.1.sf2\").midi_to_audio(out_midi, out_wav)\n",
112 | " return Audio(out_wav)\n",
113 | "from google.colab import files\n"
114 | ],
115 | "execution_count": null,
116 | "outputs": []
117 | },
118 | {
119 | "cell_type": "code",
120 | "metadata": {
121 | "id": "YEdl4mqo6IAo",
122 | "colab_type": "code",
123 | "cellView": "form",
124 | "colab": {}
125 | },
126 | "source": [
127 | "#@title Mount your Google Drive (Highly recommended)\n",
128 | "from google.colab import drive\n",
129 | "drive.mount('/content/drive')"
130 | ],
131 | "execution_count": null,
132 | "outputs": []
133 | },
134 | {
135 | "cell_type": "code",
136 | "metadata": {
137 | "id": "S-bqwERQKo2b",
138 | "colab_type": "code",
139 | "cellView": "form",
140 | "colab": {}
141 | },
142 | "source": [
143 | "#@title (OPTIONAL) Download SuperPiano original and ready-to-use training data and model\n",
144 | "!wget 'https://superpiano.s3-us-west-1.amazonaws.com/training-data-piano-no-dynamics.pkl'\n",
145 | "!wget 'https://superpiano.s3-us-west-1.amazonaws.com/SuperPianoModel.pth'"
146 | ],
147 | "execution_count": null,
148 | "outputs": []
149 | },
150 | {
151 | "cell_type": "markdown",
152 | "metadata": {
153 | "id": "wAQrJh1kjud-",
154 | "colab_type": "text"
155 | },
156 | "source": [
157 | "# PREP TRAINING DATA"
158 | ]
159 | },
160 | {
161 | "cell_type": "code",
162 | "metadata": {
163 | "id": "_wSL15svjxjN",
164 | "colab_type": "code",
165 | "cellView": "form",
166 | "colab": {}
167 | },
168 | "source": [
169 | "#@title Initialize the paths and variables\n",
170 | "# Location of your midi filesfiles\n",
171 | "midi_path = Path('/content/musicautobot/data/midi')\n",
172 | "midi_path.mkdir(parents=True, exist_ok=True)\n",
173 | "\n",
174 | "# Location to save dataset\n",
175 | "data_path = Path('/content/musicautobot')\n",
176 | "data_path.mkdir(parents=True, exist_ok=True)\n",
177 | "\n",
178 | "# Location of preprocessed numpy files\n",
179 | "numpy_path = Path('/content/musicautobot/lm')\n",
180 | "\n",
181 | "# Location to save trained model/take saved model checkpoint\n",
182 | "model_path = Path('/content/musicautobot')\n",
183 | "\n",
184 | "data_save_name = 'training-data-piano-no-dynamics.pkl'\n",
185 | "[p.mkdir(parents=True, exist_ok=True) for p in [midi_path, numpy_path, data_path, model_path]];"
186 | ],
187 | "execution_count": null,
188 | "outputs": []
189 | },
190 | {
191 | "cell_type": "markdown",
192 | "metadata": {
193 | "id": "oRqyd4H5kAyn",
194 | "colab_type": "text"
195 | },
196 | "source": [
197 | "#Upload your own MIDI files or dowload ready-to-use DataSet"
198 | ]
199 | },
200 | {
201 | "cell_type": "code",
202 | "metadata": {
203 | "id": "ACKpDyBDmp-m",
204 | "colab_type": "code",
205 | "cellView": "form",
206 | "colab": {}
207 | },
208 | "source": [
209 | "#@title Upload Files Here\n",
210 | "from google.colab import files\n",
211 | "uploaded = files.upload()"
212 | ],
213 | "execution_count": null,
214 | "outputs": []
215 | },
216 | {
217 | "cell_type": "code",
218 | "metadata": {
219 | "id": "dwVMmwXm3SXb",
220 | "colab_type": "code",
221 | "cellView": "form",
222 | "colab": {}
223 | },
224 | "source": [
225 | "#@title (The Best Choice/Works best stand-alone) Super Piano 2 Original 2500 MIDIs of Piano Music\n",
226 | "%cd /content/musicautobot/data/midi\n",
227 | "!wget 'https://github.com/asigalov61/SuperPiano/raw/master/Super_Piano_2_MIDI_DataSet_CC_BY_NC_SA.zip'\n",
228 | "!unzip -j 'Super_Piano_2_MIDI_DataSet_CC_BY_NC_SA.zip'"
229 | ],
230 | "execution_count": null,
231 | "outputs": []
232 | },
233 | {
234 | "cell_type": "code",
235 | "metadata": {
236 | "id": "GGIX4-ptrwUa",
237 | "colab_type": "code",
238 | "cellView": "form",
239 | "colab": {}
240 | },
241 | "source": [
242 | "#@title (Second Best Choice/Works best stand-alone) Alex Piano Only Drafts Original 1500 MIDIs \n",
243 | "%cd /content/musicautobot/data/midi\n",
244 | "!wget 'https://github.com/asigalov61/AlexMIDIDataSet/raw/master/AlexMIDIDataSet-CC-BY-NC-SA-All-Drafts-Piano-Only.zip'\n",
245 | "!unzip -j 'AlexMIDIDataSet-CC-BY-NC-SA-All-Drafts-Piano-Only.zip'"
246 | ],
247 | "execution_count": null,
248 | "outputs": []
249 | },
250 | {
251 | "cell_type": "code",
252 | "metadata": {
253 | "id": "vuoi5nZb3dL_",
254 | "colab_type": "code",
255 | "cellView": "form",
256 | "colab": {}
257 | },
258 | "source": [
259 | "#@title (Optional) Google Magenta MAESTRO Piano MIDI Dataset (~1300 MIDIs)\n",
260 | "%cd /content/musicautobot/data/midi\n",
261 | "!wget 'https://storage.googleapis.com/magentadata/datasets/maestro/v2.0.0/maestro-v2.0.0-midi.zip'\n",
262 | "!unzip -j maestro-v2.0.0-midi.zip"
263 | ],
264 | "execution_count": null,
265 | "outputs": []
266 | },
267 | {
268 | "cell_type": "markdown",
269 | "metadata": {
270 | "id": "yHEGFP-IOqaE",
271 | "colab_type": "text"
272 | },
273 | "source": [
274 | "#MIDI PROCESSING"
275 | ]
276 | },
277 | {
278 | "cell_type": "code",
279 | "metadata": {
280 | "id": "w_0l5fZfbEov",
281 | "colab_type": "code",
282 | "cellView": "form",
283 | "colab": {}
284 | },
285 | "source": [
286 | "#@title Calculate and display number of indexed MIDI files\n",
287 | "# num_tracks = [1, 2] # number of tracks to support\n",
288 | "cutoff = 5 # max instruments\n",
289 | "min_variation = 3 # minimum number of different midi notes played\n",
290 | "# max_dur = 128\n",
291 | "\n",
292 | "midi_files = get_files(midi_path, '.midi', recurse=False); len(midi_files)"
293 | ],
294 | "execution_count": null,
295 | "outputs": []
296 | },
297 | {
298 | "cell_type": "code",
299 | "metadata": {
300 | "id": "xLe-Jy7ebkKL",
301 | "colab_type": "code",
302 | "cellView": "form",
303 | "colab": {}
304 | },
305 | "source": [
306 | "#@title Parse, Compress, and Convert MIDI files into Numpy format\n",
307 | "def process_metadata(midi_file):\n",
308 | " # Get outfile and check if it exists\n",
309 | " out_file = numpy_path/midi_file.relative_to(midi_path).with_suffix('.npy')\n",
310 | " out_file.parent.mkdir(parents=True, exist_ok=True)\n",
311 | " if out_file.exists(): return\n",
312 | " \n",
313 | " npenc = transform_midi(midi_file)\n",
314 | " if npenc is not None: np.save(out_file, npenc)\n",
315 | "\n",
316 | "#===============================================================\n",
317 | "\n",
318 | "def transform_midi(midi_file):\n",
319 | " input_path = midi_file\n",
320 | " \n",
321 | " # Part 1: Filter out midi tracks (drums, repetitive instruments, etc.)\n",
322 | " try: \n",
323 | "# if duet_only and num_piano_tracks(input_path) not in [1, 2]: return None\n",
324 | " input_file = compress_midi_file(input_path, min_variation=min_variation, cutoff=cutoff) # remove non note tracks and standardize instruments\n",
325 | " \n",
326 | " if input_file is None: return None\n",
327 | " except Exception as e:\n",
328 | " if 'badly form' in str(e): return None # ignore badly formatted midi errors\n",
329 | " if 'out of range' in str(e): return None # ignore badly formatted midi errors\n",
330 | " print('Error parsing midi', input_path, e)\n",
331 | " return None\n",
332 | " \n",
333 | " # Part 2. Compress rests and long notes\n",
334 | " stream = file2stream(input_file) # 1.\n",
335 | " try:\n",
336 | " chordarr = stream2chordarr(stream) # 2. max_dur = quarter_len * sample_freq (4). 128 = 8 bars\n",
337 | " except Exception as e:\n",
338 | " print('Could not encode to chordarr:', input_path, e)\n",
339 | " print(traceback.format_exc())\n",
340 | " return None\n",
341 | " \n",
342 | " # Part 3. Compress song rests - Don't want songs with really long pauses \n",
343 | " # (this happens because we filter out midi tracks).\n",
344 | " chord_trim = trim_chordarr_rests(chordarr)\n",
345 | " chord_short = shorten_chordarr_rests(chord_trim)\n",
346 | " delta_trim = chord_trim.shape[0] - chord_short.shape[0]\n",
347 | " if delta_trim > 500: \n",
348 | " print(f'Removed {delta_trim} rests from {input_path}. Skipping song')\n",
349 | " return None\n",
350 | " chordarr = chord_short\n",
351 | " \n",
352 | " # Part 3. Chord array to numpy\n",
353 | " npenc = chordarr2npenc(chordarr)\n",
354 | " if not is_valid_npenc(npenc, input_path=input_path):\n",
355 | " return None\n",
356 | " \n",
357 | " return npenc\n",
358 | "\n",
359 | "#===============================================================\n",
360 | "def timeout_func(data, seconds):\n",
361 | " print(\"Timeout:\", seconds, data.get('midi'))\n",
362 | "\n",
363 | "#===============================================================\n",
364 | "processed = process_all(process_metadata, midi_files, timeout=120, timeout_func=timeout_func)"
365 | ],
366 | "execution_count": null,
367 | "outputs": []
368 | },
369 | {
370 | "cell_type": "code",
371 | "metadata": {
372 | "id": "Rjdoka86dUrS",
373 | "colab_type": "code",
374 | "cellView": "form",
375 | "colab": {}
376 | },
377 | "source": [
378 | "#@title Calculate and display number of resulting Numpy files\n",
379 | "def create_databunch(files, data_save_name, path=data_path):\n",
380 | " save_file = path/data_save_name\n",
381 | " if save_file.exists():\n",
382 | " data = load_data(path, data_save_name)\n",
383 | " else:\n",
384 | " save_file.parent.mkdir(exist_ok=True, parents=True)\n",
385 | " vocab = MusicVocab.create()\n",
386 | " processors = [OpenNPFileProcessor(), MusicItemProcessor()]\n",
387 | "\n",
388 | " data = MusicDataBunch.from_files(files, path, processors=processors, encode_position=True)\n",
389 | " data.save(data_save_name)\n",
390 | " return data\n",
391 | "numpy_files = get_files(numpy_path, extensions='.npy', recurse=False); len(numpy_files)"
392 | ],
393 | "execution_count": null,
394 | "outputs": []
395 | },
396 | {
397 | "cell_type": "code",
398 | "metadata": {
399 | "id": "y8fu3PVgdZW4",
400 | "colab_type": "code",
401 | "cellView": "form",
402 | "colab": {}
403 | },
404 | "source": [
405 | "#@title Create final training dataset file (training-data-piano-no-dynamics.pkl)\n",
406 | "all_data = create_databunch(numpy_files, data_save_name=data_save_name); all_data"
407 | ],
408 | "execution_count": null,
409 | "outputs": []
410 | },
411 | {
412 | "cell_type": "markdown",
413 | "metadata": {
414 | "id": "IRvnFMqWP1Ai",
415 | "colab_type": "text"
416 | },
417 | "source": [
418 | "# TRAIN, SAVE, AND PLOT MODEL PERFOMANCE"
419 | ]
420 | },
421 | {
422 | "cell_type": "code",
423 | "metadata": {
424 | "id": "AkrdRghxkXzB",
425 | "colab_type": "code",
426 | "cellView": "form",
427 | "colab": {}
428 | },
429 | "source": [
430 | "#@title Initialize the model\n",
431 | "!nvidia-smi\n",
432 | "batch_size = 32\n",
433 | "encode_position = True\n",
434 | "config = default_config()\n",
435 | "dl_tfms = [batch_position_tfm] if encode_position else []\n",
436 | "data = load_data(data_path, data_save_name, bs=batch_size, encode_position=encode_position, transpose_range=[0, 12], dl_tfms=dl_tfms)\n",
437 | "learn = music_model_learner(data, config=config.copy(), metrics=[accuracy, error_rate])\n",
438 | "!nvidia-smi\n"
439 | ],
440 | "execution_count": null,
441 | "outputs": []
442 | },
443 | {
444 | "cell_type": "code",
445 | "metadata": {
446 | "id": "xXAD2KWazW0d",
447 | "colab_type": "code",
448 | "cellView": "form",
449 | "colab": {}
450 | },
451 | "source": [
452 | "#@title (Optional) Load Existing Model Checkpoint\n",
453 | "config = default_config()\n",
454 | "pretrained_path = Path('/content/musicautobot/SuperPianoModel.pth')\n",
455 | "learn = music_model_learner(data, config=config, pretrained_path=pretrained_path, metrics=[accuracy, error_rate])"
456 | ],
457 | "execution_count": null,
458 | "outputs": []
459 | },
460 | {
461 | "cell_type": "code",
462 | "metadata": {
463 | "id": "04QoLCIEH2v7",
464 | "colab_type": "code",
465 | "cellView": "form",
466 | "colab": {}
467 | },
468 | "source": [
469 | "#@title Find the optimum learning rate first by running this cell\n",
470 | "learn.lr_find()\n",
471 | "learn.recorder.plot()\n",
472 | "learn.recorder.plot_lr(show_moms=True)"
473 | ],
474 | "execution_count": null,
475 | "outputs": []
476 | },
477 | {
478 | "cell_type": "code",
479 | "metadata": {
480 | "id": "Eq55lYQlkhht",
481 | "colab_type": "code",
482 | "cellView": "form",
483 | "colab": {}
484 | },
485 | "source": [
486 | "#@title Start/Continue Training\n",
487 | "number_of_training_epochs = 2 #@param {type:\"slider\", min:0, max:10, step:1}\n",
488 | "optimum_learning_rate = 0.01 #@param {type:\"number\"}\n",
489 | "\n",
490 | "learn.fit_one_cycle(number_of_training_epochs, optimum_learning_rate)"
491 | ],
492 | "execution_count": null,
493 | "outputs": []
494 | },
495 | {
496 | "cell_type": "code",
497 | "metadata": {
498 | "id": "3pvhIoY3klFe",
499 | "colab_type": "code",
500 | "cellView": "form",
501 | "colab": {}
502 | },
503 | "source": [
504 | "#@title Save and Plot\n",
505 | "learn.save('/content/musicautobot/SuperPianoModel')\n",
506 | "learn.recorder.plot_lr(show_moms=True)"
507 | ],
508 | "execution_count": null,
509 | "outputs": []
510 | },
511 | {
512 | "cell_type": "markdown",
513 | "metadata": {
514 | "id": "EckFLJkjJdFg",
515 | "colab_type": "text"
516 | },
517 | "source": [
518 | "# GENERATE MUSIC WITH THE MODEL"
519 | ]
520 | },
521 | {
522 | "cell_type": "markdown",
523 | "metadata": {
524 | "id": "FmhNm2TcJdFh",
525 | "colab_type": "text"
526 | },
527 | "source": [
528 | "## SETUP VARIABLES AND LOAD/RE-LOAD THE MODEL (just in case)"
529 | ]
530 | },
531 | {
532 | "cell_type": "code",
533 | "metadata": {
534 | "id": "hH7drZxkJdFi",
535 | "colab_type": "code",
536 | "cellView": "form",
537 | "colab": {}
538 | },
539 | "source": [
540 | "#@title Setup Paths and Intialize the Model\n",
541 | "# Location of your midi files\n",
542 | "midi_path = Path('/content/musicautobot')\n",
543 | "\n",
544 | "# Location of saved datset\n",
545 | "data_path = Path('/content/musicautobot')\n",
546 | "\n",
547 | "# Data and Vocab variables initialization\n",
548 | "data = MusicDataBunch.empty(data_path) #for pretrained models\n",
549 | "vocab = data.vocab\n",
550 | "\n",
551 | "# Location of pretrained model\n",
552 | "pretrained_path = Path('/content/musicautobot/SuperPianoModel.pth')\n",
553 | "pretrained_path.parent.mkdir(parents=True, exist_ok=True)\n",
554 | "\n",
555 | "# Initialize the model\n",
556 | "config = default_config()\n",
557 | "learn = music_model_learner(data, config=config, pretrained_path=pretrained_path)"
558 | ],
559 | "execution_count": null,
560 | "outputs": []
561 | },
562 | {
563 | "cell_type": "markdown",
564 | "metadata": {
565 | "id": "G3HDp9EMJdFr",
566 | "colab_type": "text"
567 | },
568 | "source": [
569 | "### PREDICTION"
570 | ]
571 | },
572 | {
573 | "cell_type": "markdown",
574 | "metadata": {
575 | "id": "UDWCdsHFJdFr",
576 | "colab_type": "text"
577 | },
578 | "source": [
579 | "## Choose existing midi file as a starting point"
580 | ]
581 | },
582 | {
583 | "cell_type": "code",
584 | "metadata": {
585 | "id": "tJGaOvmbt08K",
586 | "colab_type": "code",
587 | "cellView": "form",
588 | "colab": {}
589 | },
590 | "source": [
591 | "#@title Upload your seed MIDI (will purge all MID/MIDI files you might've uploaded before)\n",
592 | "%cd /content/musicautobot\n",
593 | "!rm *.mid *.midi\n",
594 | "uploaded = files.upload()\n",
595 | "midi_files = get_files(midi_path, recurse=False, extensions='.mid'); midi_files[:5]\n",
596 | "idx = 0\n",
597 | "f = midi_files[idx]; f"
598 | ],
599 | "execution_count": null,
600 | "outputs": []
601 | },
602 | {
603 | "cell_type": "markdown",
604 | "metadata": {
605 | "id": "nJShT9HKJdFw",
606 | "colab_type": "text"
607 | },
608 | "source": [
609 | "## Trim (use seed from a MIDI file to predict next sequence/continuation)\n",
610 | "\n"
611 | ]
612 | },
613 | {
614 | "cell_type": "code",
615 | "metadata": {
616 | "id": "pPvOU-sUPqGc",
617 | "colab_type": "code",
618 | "cellView": "form",
619 | "colab": {}
620 | },
621 | "source": [
622 | "##@title Setup Pianoroll Output :) { run: \"auto\" }\n",
623 | "graphs_length_inches = 18 #@param {type:\"slider\", min:0, max:20, step:1}\n",
624 | "notes_graph_height = 5 #@param {type:\"slider\", min:0, max:20, step:1}\n",
625 | "\n",
626 | "import librosa\n",
627 | "import numpy as np\n",
628 | "import pretty_midi\n",
629 | "import pypianoroll\n",
630 | "from pypianoroll import Multitrack, Track\n",
631 | "import matplotlib\n",
632 | "import matplotlib.pyplot as plt\n",
633 | "#matplotlib.use('SVG')\n",
634 | "# For plotting\n",
635 | "import mir_eval.display\n",
636 | "import librosa.display\n",
637 | "%matplotlib inline\n",
638 | "\n",
639 | "\n",
640 | "#midi_data = pretty_midi.PrettyMIDI('/content/MusicTransformer-Pytorch/output/rand.mid')\n",
641 | "\n",
642 | "def plot_piano_roll(pm, start_pitch, end_pitch, fs=100):\n",
643 | " # Use librosa's specshow function for displaying the piano roll\n",
644 | " librosa.display.specshow(pm.get_piano_roll(fs)[start_pitch:end_pitch],\n",
645 | " hop_length=1, sr=fs, x_axis='time', y_axis='cqt_note',\n",
646 | " fmin=pretty_midi.note_number_to_hz(start_pitch))\n",
647 | "\n",
648 | "\n",
649 | "\n",
650 | "roll = np.zeros([int(graphs_length_inches), 128])\n"
651 | ],
652 | "execution_count": null,
653 | "outputs": []
654 | },
655 | {
656 | "cell_type": "code",
657 | "metadata": {
658 | "id": "WUPmoGqcJdFx",
659 | "colab_type": "code",
660 | "cellView": "form",
661 | "colab": {}
662 | },
663 | "source": [
664 | "#@title Show/Plot/Listen to the seed uploaded above. You can also run this cell to see Seed Continuation output below\n",
665 | "MIDI_cutoff_beat = 20 #@param {type:\"slider\", min:0, max:100, step:1}\n",
666 | "cutoff_beat = 20\n",
667 | "item = MusicItem.from_file(f, data.vocab)\n",
668 | "seed_item = item.trim_to_beat(cutoff_beat)\n",
669 | "\n",
670 | "seed_item.stream.write('midi', '/content/musicautobot/seed_item.mid')\n",
671 | "\n",
672 | "roll = np.zeros([int(graphs_length_inches), 128])\n",
673 | "midi_data = pretty_midi.PrettyMIDI('/content/musicautobot/seed_item.mid')\n",
674 | "\n",
675 | "plt.figure(figsize=[graphs_length_inches, notes_graph_height])\n",
676 | "ax2 = plot_piano_roll(midi_data, 24, 84)\n",
677 | "plt.show(block=False)\n",
678 | "\n",
679 | "play_wav(seed_item.stream)"
680 | ],
681 | "execution_count": null,
682 | "outputs": []
683 | },
684 | {
685 | "cell_type": "markdown",
686 | "metadata": {
687 | "id": "W_h-A5huKxXu",
688 | "colab_type": "text"
689 | },
690 | "source": [
691 | "## GENERATE (CHOOSE ONE OPTION BELOW)"
692 | ]
693 | },
694 | {
695 | "cell_type": "markdown",
696 | "metadata": {
697 | "id": "EerOfXwwsOBD",
698 | "colab_type": "text"
699 | },
700 | "source": [
701 | "### GENERATE w/starting sequence (Continuation)"
702 | ]
703 | },
704 | {
705 | "cell_type": "code",
706 | "metadata": {
707 | "id": "2LA7EeVpKh4Y",
708 | "colab_type": "code",
709 | "cellView": "form",
710 | "colab": {}
711 | },
712 | "source": [
713 | "#@title Seed Continuation\n",
714 | "number_of_tokens_to_generate = 256 #@param {type:\"slider\", min:0, max:4096, step:64}\n",
715 | "max_model_temperature = 0.7 #@param {type:\"slider\", min:0, max:4, step:0.1}\n",
716 | "min_model_temperature = 1.3 #@param {type:\"slider\", min:0, max:4, step:0.1}\n",
717 | "model_top_k = 30 #@param {type:\"slider\", min:0, max:50, step:1}\n",
718 | "model_top_p = 0.9 #@param {type:\"slider\", min:0, max:1, step:0.1}\n",
719 | "minimum_number_of_bars_to_generate = 8 #@param {type:\"slider\", min:0, max:64, step:1}\n",
720 | "seed_item = MusicItem.from_file('seed_item.mid', data.vocab)\n",
721 | "pred, full = learn.predict(seed_item, n_words=number_of_tokens_to_generate, temperatures=(max_model_temperature, min_model_temperature), min_bars=minimum_number_of_bars_to_generate, top_k=model_top_k, top_p=model_top_p)\n",
722 | "#pred.show()\n",
723 | "pred.stream.write('midi', '/content/musicautobot/continuation.mid')\n",
724 | "\n",
725 | "\n",
726 | "roll = np.zeros([int(graphs_length_inches), 128])\n",
727 | "midi_data = pretty_midi.PrettyMIDI('/content/musicautobot/continuation.mid')\n",
728 | "\n",
729 | "plt.figure(figsize=[graphs_length_inches, notes_graph_height])\n",
730 | "ax2 = plot_piano_roll(midi_data, 24, 84)\n",
731 | "plt.show(block=False)\n",
732 | "\n",
733 | "play_wav(pred.stream)"
734 | ],
735 | "execution_count": null,
736 | "outputs": []
737 | },
738 | {
739 | "cell_type": "code",
740 | "metadata": {
741 | "id": "UZg6f8mVJdF_",
742 | "colab_type": "code",
743 | "cellView": "form",
744 | "colab": {}
745 | },
746 | "source": [
747 | "#@title Would you like to add generated continuation to the seed/previous section??? If yes, run this cell, if not, go back and start over.\n",
748 | "seed_item = seed_item.append(pred)\n",
749 | "#seed_item.show()\n",
750 | "\n",
751 | "seed_item.stream.write('midi', '/content/musicautobot/seed_continuation.mid')\n",
752 | "\n",
753 | "roll = np.zeros([int(graphs_length_inches), 128])\n",
754 | "midi_data = pretty_midi.PrettyMIDI('/content/musicautobot/seed_continuation.mid')\n",
755 | "\n",
756 | "plt.figure(figsize=[graphs_length_inches, notes_graph_height])\n",
757 | "ax2 = plot_piano_roll(midi_data, 24, 84)\n",
758 | "plt.show(block=False)\n",
759 | "\n",
760 | "play_wav(seed_item.stream)"
761 | ],
762 | "execution_count": null,
763 | "outputs": []
764 | },
765 | {
766 | "cell_type": "markdown",
767 | "metadata": {
768 | "id": "b-hAoe5HJdGS",
769 | "colab_type": "text"
770 | },
771 | "source": [
772 | "### GENERATE w/o a starting sequence (Performance)"
773 | ]
774 | },
775 | {
776 | "cell_type": "code",
777 | "metadata": {
778 | "id": "h9gF6rt7JdGU",
779 | "colab_type": "code",
780 | "cellView": "form",
781 | "colab": {}
782 | },
783 | "source": [
784 | "#@title Original Uninfluenced Performance\n",
785 | "number_of_tokens_to_generate = 1024 #@param {type:\"slider\", min:0, max:4096, step:64}\n",
786 | "max_model_temperature = 1.4 #@param {type:\"slider\", min:0, max:4, step:0.1}\n",
787 | "min_model_temperature = 0.7 #@param {type:\"slider\", min:0, max:4, step:0.1}\n",
788 | "model_top_k = 20 #@param {type:\"slider\", min:0, max:50, step:1}\n",
789 | "model_top_p = 0.8 #@param {type:\"slider\", min:0, max:1, step:0.1}\n",
790 | "minimum_number_of_bars_to_generate = 8 #@param {type:\"slider\", min:0, max:64, step:1}\n",
791 | "\n",
792 | "empty_item = MusicItem.empty(vocab)\n",
793 | "pred, full = learn.predict(empty_item, n_words=number_of_tokens_to_generate, temperatures=(max_model_temperature, min_model_temperature), min_bars=minimum_number_of_bars_to_generate, top_k=model_top_k, top_p=model_top_p)\n",
794 | "#pred.show()\n",
795 | "pred.stream.write('midi', '/content/musicautobot/performance.mid')\n",
796 | "\n",
797 | "roll = np.zeros([int(graphs_length_inches), 128])\n",
798 | "midi_data = pretty_midi.PrettyMIDI('/content/musicautobot/performance.mid')\n",
799 | "\n",
800 | "plt.figure(figsize=[graphs_length_inches, notes_graph_height])\n",
801 | "ax2 = plot_piano_roll(midi_data, 24, 84)\n",
802 | "plt.show(block=False)\n",
803 | "\n",
804 | "play_wav(pred.stream)"
805 | ],
806 | "execution_count": null,
807 | "outputs": []
808 | }
809 | ]
810 | }
--------------------------------------------------------------------------------
/SuperPiano5_(Reformer_TPU).ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "accelerator": "TPU",
6 | "colab": {
7 | "name": "SuperPiano5 (Reformer_TPU).ipynb",
8 | "private_outputs": true,
9 | "provenance": [],
10 | "collapsed_sections": [],
11 | "toc_visible": true,
12 | "include_colab_link": true
13 | },
14 | "kernelspec": {
15 | "display_name": "Python 3",
16 | "language": "python",
17 | "name": "python3"
18 | },
19 | "language_info": {
20 | "codemirror_mode": {
21 | "name": "ipython",
22 | "version": 3
23 | },
24 | "file_extension": ".py",
25 | "mimetype": "text/x-python",
26 | "name": "python",
27 | "nbconvert_exporter": "python",
28 | "pygments_lexer": "ipython3",
29 | "version": "3.7.7"
30 | }
31 | },
32 | "cells": [
33 | {
34 | "cell_type": "markdown",
35 | "metadata": {
36 | "id": "view-in-github",
37 | "colab_type": "text"
38 | },
39 | "source": [
40 | "
"
41 | ]
42 | },
43 | {
44 | "cell_type": "markdown",
45 | "metadata": {
46 | "id": "lgn4KUAATtXS"
47 | },
48 | "source": [
49 | "# Super Piano 5 (v.0.5)\r\n",
50 | "\r\n",
51 | "Uses integer version of the https://github.com/asigalov61/Tegridy-MIDI-Dataset/blob/master/Tegridy-Piano-CC-BY-NC-SA.zip\r\n",
52 | "\r\n",
53 | "Most of the colab as found here:\r\n",
54 | "\r\n",
55 | "https://github.com/jlilleberg/Philosophical-Text-Generation-using-Reformers"
56 | ]
57 | },
58 | {
59 | "cell_type": "code",
60 | "metadata": {
61 | "id": "QINqPZH6FzB3"
62 | },
63 | "source": [
64 | "# Install dependencies\n",
65 | "\n",
66 | "!git clone https://github.com/asigalov61/tegridy-tools\n",
67 | "%cd /content/tegridy-tools/tegridy-tools/\n",
68 | "import TMIDI\n",
69 | "%cd /content/\n",
70 | "\n",
71 | "!wget https://github.com/asigalov61/SuperPiano/raw/master/MUSIC_INT_EVAL_DATASET.zip\n",
72 | "\n",
73 | "!pip install --upgrade -q jax\n",
74 | "!pip install --upgrade -q jaxlib\n",
75 | "!pip install --upgrade -q trax==1.3.6\n",
76 | "!pip install --upgrade -q sentencepiece\n",
77 | "!pip install --upgrade -q gin \n",
78 | "\n",
79 | "# Make sure the Colab Runtime is set to Accelerator: TPU.\n",
80 | "import requests\n",
81 | "import os\n",
82 | "if 'TPU_DRIVER_MODE' not in globals():\n",
83 | " url = 'http://' + os.environ['COLAB_TPU_ADDR'].split(':')[0] + ':8475/requestversion/tpu_driver0.1-dev20191206'\n",
84 | " resp = requests.post(url)\n",
85 | " TPU_DRIVER_MODE = 1\n",
86 | "\n",
87 | "# The following is required to use TPU Driver as JAX's backend.\n",
88 | "from jax.config import config\n",
89 | "config.FLAGS.jax_xla_backend = \"tpu_driver\"\n",
90 | "config.FLAGS.jax_backend_target = \"grpc://\" + os.environ['COLAB_TPU_ADDR']\n",
91 | "print(config.FLAGS.jax_backend_target)"
92 | ],
93 | "execution_count": null,
94 | "outputs": []
95 | },
96 | {
97 | "cell_type": "code",
98 | "metadata": {
99 | "id": "s4-aGTZBUxAy"
100 | },
101 | "source": [
102 | "!wget https://github.com/asigalov61/SuperPiano/raw/master/MUSIC_INT_EVAL_DATASET.zip\r\n",
103 | "!unzip MUSIC_INT_EVAL_DATASET.zip"
104 | ],
105 | "execution_count": null,
106 | "outputs": []
107 | },
108 | {
109 | "cell_type": "code",
110 | "metadata": {
111 | "id": "pv0PuxC3F-jn"
112 | },
113 | "source": [
114 | "import gin\n",
115 | "import os\n",
116 | "import numpy as np\n",
117 | "from scipy.special import softmax\n",
118 | "\n",
119 | "# Zipping and downloading files\n",
120 | "from google.colab import files\n",
121 | "import shutil\n",
122 | "\n",
123 | "# Trax\n",
124 | "import jax\n",
125 | "import trax\n",
126 | "from trax.data import inputs\n",
127 | "import jax.numpy as jnp\n",
128 | "\n",
129 | "# NLP Vocab Generation\n",
130 | "import sentencepiece as spm\n",
131 | "\n",
132 | "# TensorFlow\n",
133 | "from tensorflow.compat.v1.io.gfile import GFile\n",
134 | "import tensorflow as tf"
135 | ],
136 | "execution_count": null,
137 | "outputs": []
138 | },
139 | {
140 | "cell_type": "code",
141 | "metadata": {
142 | "id": "L7shBqm0T6rz"
143 | },
144 | "source": [
145 | "# This is for the future MIDI Processor code/section.\r\n",
146 | "# This is to create custom datasets.\r\n",
147 | "\r\n",
148 | "# TXT2, STR2 = TMIDI.Tegridy_TXT_to_INT_Converter(TXT1)\r\n",
149 | "# TXT3 = '\\n'.join([str(elem) for elem in TXT2])\r\n",
150 | "# with open('/content/INT_DATASET.TXT', 'a') as t:\r\n",
151 | "# t.write(TXT3)"
152 | ],
153 | "execution_count": null,
154 | "outputs": []
155 | },
156 | {
157 | "cell_type": "code",
158 | "metadata": {
159 | "id": "yRnIoCBkNXyd"
160 | },
161 | "source": [
162 | "# Load the dataset\n",
163 | "with GFile('/content/MUSIC_INT_EVAL_DATASET.TXT') as f:\n",
164 | " text = f.read()"
165 | ],
166 | "execution_count": null,
167 | "outputs": []
168 | },
169 | {
170 | "cell_type": "code",
171 | "metadata": {
172 | "id": "_l9Znw2bS-Pg"
173 | },
174 | "source": [
175 | "# Train a BPE model on the dataset\n",
176 | "spm.SentencePieceTrainer.train('--input=/content/MUSIC_INT_EVAL_DATASET.TXT \\\n",
177 | " --model_prefix=cp.320 \\\n",
178 | " --vocab_size=320 \\\n",
179 | " --model_type=bpe')\n",
180 | "# Load BPE vocabulary\n",
181 | "TOKENIZER = spm.SentencePieceProcessor() \n",
182 | "TOKENIZER.load('cp.320.model')"
183 | ],
184 | "execution_count": null,
185 | "outputs": []
186 | },
187 | {
188 | "cell_type": "code",
189 | "metadata": {
190 | "id": "OQwhEqJzS-I2"
191 | },
192 | "source": [
193 | "# Tokenize (set to max for the provided dataset)\n",
194 | "\n",
195 | "IDS = TOKENIZER.EncodeAsIds(text[:1600000])\n",
196 | "IDS = np.asarray(IDS, dtype=np.int32)\n",
197 | "PAD_AMOUNT = 512 * 1024 - len(IDS)\n",
198 | "print(\"Number of tokens:\", IDS.shape[0])"
199 | ],
200 | "execution_count": null,
201 | "outputs": []
202 | },
203 | {
204 | "cell_type": "code",
205 | "metadata": {
206 | "id": "bdKnx2FyS-AO"
207 | },
208 | "source": [
209 | "# Set up the data pipeline.\n",
210 | "def my_inputs(n_devices):\n",
211 | " while True:\n",
212 | " inputs = []\n",
213 | " mask = []\n",
214 | " pad_amounts = np.random.choice(PAD_AMOUNT, n_devices)\n",
215 | " for i in range(n_devices):\n",
216 | " inputs.append(np.pad(IDS, (pad_amounts[i], PAD_AMOUNT - pad_amounts[i]), # Pad IDS by different amount for each device\n",
217 | " mode='constant'))\n",
218 | " mask.append(np.pad(np.ones_like(IDS, dtype=np.float32),\n",
219 | " (pad_amounts[i], PAD_AMOUNT - pad_amounts[i]),\n",
220 | " mode='constant'))\n",
221 | " inputs = np.stack(inputs)\n",
222 | " mask = np.stack(mask)\n",
223 | " yield (inputs, inputs, mask)\n",
224 | "\n",
225 | "print(\"(device count, tokens per device) = \",\n",
226 | " next(my_inputs(trax.fastmath.device_count()))[0].shape)"
227 | ],
228 | "execution_count": null,
229 | "outputs": []
230 | },
231 | {
232 | "cell_type": "code",
233 | "metadata": {
234 | "id": "-NeFGlGGS959"
235 | },
236 | "source": [
237 | "# Configure hyperparameters.\n",
238 | "gin.parse_config(\"\"\"\n",
239 | "import trax.layers\n",
240 | "import trax.models\n",
241 | "import trax.optimizers\n",
242 | "import trax.data.inputs\n",
243 | "import trax.supervised.trainer_lib\n",
244 | "\n",
245 | "# Parameters that will vary between experiments:\n",
246 | "# ==============================================================================\n",
247 | "train.model = @trax.models.ReformerLM\n",
248 | "# Model will have 6 layers, alternating between the LSH attention\n",
249 | "# and local attention within a certain context window.\n",
250 | "n_layers = 6\n",
251 | "attn_type = [\n",
252 | " @trax.layers.SelfAttention,\n",
253 | " @LSHSelfAttention, \n",
254 | " @trax.layers.SelfAttention,\n",
255 | " @LSHSelfAttention,\n",
256 | " @trax.layers.SelfAttention,\n",
257 | " @LSHSelfAttention,\n",
258 | " ]\n",
259 | "share_qk = False # LSH attention ignores this flag and always shares q & k\n",
260 | "n_heads = 2\n",
261 | "attn_kv = 64\n",
262 | "dropout = 0.05\n",
263 | "n_tokens = 524288\n",
264 | "\n",
265 | "# Parameters for multifactor:\n",
266 | "# ==============================================================================\n",
267 | "multifactor.constant = 0.01\n",
268 | "multifactor.factors = 'constant * linear_warmup * cosine_decay'\n",
269 | "multifactor.warmup_steps = 100\n",
270 | "multifactor.steps_per_cycle = 900\n",
271 | "\n",
272 | "# Parameters for Adam:\n",
273 | "# ==============================================================================\n",
274 | "Adam.weight_decay_rate=0.0\n",
275 | "Adam.b1 = 0.86\n",
276 | "Adam.b2 = 0.92\n",
277 | "Adam.eps = 1e-9\n",
278 | "\n",
279 | "# Parameters for SelfAttention:\n",
280 | "# ==============================================================================\n",
281 | "trax.layers.SelfAttention.attention_dropout = 0.05\n",
282 | "trax.layers.SelfAttention.chunk_len = 64\n",
283 | "trax.layers.SelfAttention.n_chunks_before = 1\n",
284 | "trax.layers.SelfAttention.n_parallel_heads = 1\n",
285 | "\n",
286 | "# Parameters for LSHSelfAttention:\n",
287 | "# ==============================================================================\n",
288 | "LSHSelfAttention.attention_dropout = 0.0\n",
289 | "LSHSelfAttention.chunk_len = 64\n",
290 | "LSHSelfAttention.n_buckets = [64, 128]\n",
291 | "LSHSelfAttention.n_chunks_after = 0\n",
292 | "LSHSelfAttention.n_chunks_before = 1\n",
293 | "LSHSelfAttention.n_hashes = 1\n",
294 | "LSHSelfAttention.n_parallel_heads = 1\n",
295 | "LSHSelfAttention.predict_drop_len = 128\n",
296 | "LSHSelfAttention.predict_mem_len = 1024\n",
297 | "\n",
298 | "# Parameters for ReformerLM:\n",
299 | "# ==============================================================================\n",
300 | "ReformerLM.attention_type = %attn_type\n",
301 | "ReformerLM.d_attention_key = %attn_kv\n",
302 | "ReformerLM.d_attention_value = %attn_kv\n",
303 | "ReformerLM.d_model = 256\n",
304 | "ReformerLM.d_ff = 512\n",
305 | "ReformerLM.dropout = %dropout\n",
306 | "ReformerLM.ff_activation = @trax.layers.Relu\n",
307 | "ReformerLM.max_len = %n_tokens\n",
308 | "ReformerLM.mode = 'train'\n",
309 | "ReformerLM.n_heads = %n_heads\n",
310 | "ReformerLM.n_layers = %n_layers\n",
311 | "ReformerLM.vocab_size = 320\n",
312 | "ReformerLM.axial_pos_shape = (512, 1024)\n",
313 | "ReformerLM.d_axial_pos_embs= (64, 192)\n",
314 | "\"\"\")"
315 | ],
316 | "execution_count": null,
317 | "outputs": []
318 | },
319 | {
320 | "cell_type": "code",
321 | "metadata": {
322 | "id": "X8ay-6VxS9xw"
323 | },
324 | "source": [
325 | "# Trainer.\n",
326 | "output_dir = os.path.expanduser('model')\n",
327 | "!rm -f ~/model/model.pkl.gz # Remove old model\n",
328 | "\n",
329 | "trainer = trax.supervised.Trainer(\n",
330 | " model=trax.models.ReformerLM,\n",
331 | " loss_fn=trax.layers.CrossEntropyLoss(),\n",
332 | " optimizer=trax.optimizers.Adam,\n",
333 | " lr_schedule=trax.lr.multifactor(),\n",
334 | " inputs=trax.data.inputs.Inputs(my_inputs),\n",
335 | " output_dir=output_dir)"
336 | ],
337 | "execution_count": null,
338 | "outputs": []
339 | },
340 | {
341 | "cell_type": "code",
342 | "metadata": {
343 | "id": "Qf0HITY7Wz8C"
344 | },
345 | "source": [
346 | "# Train Model\n",
347 | "import tqdm\n",
348 | "for _ in tqdm.tqdm(range(50)):\n",
349 | " trainer.train_epoch(n_steps=100, n_eval_steps=20)"
350 | ],
351 | "execution_count": null,
352 | "outputs": []
353 | },
354 | {
355 | "cell_type": "code",
356 | "metadata": {
357 | "id": "JEikLctyte-m"
358 | },
359 | "source": [
360 | "# Zip directory contents\n",
361 | "shutil.make_archive(\"project\", \"zip\", \".\")\n",
362 | "\n",
363 | "# Download zipped directory\n",
364 | "files.download('project.zip')"
365 | ],
366 | "execution_count": null,
367 | "outputs": []
368 | },
369 | {
370 | "cell_type": "code",
371 | "metadata": {
372 | "id": "FLebeiAFrItK"
373 | },
374 | "source": [
375 | "# In the Reformer paper, increasing the number of hashing rounds helps with quality. \n",
376 | "# The number of hashing rounds at can be increased at evaluation time only.\n",
377 | "gin.parse_config(\"\"\"LSHSelfAttention.n_hashes = 8\"\"\")"
378 | ],
379 | "execution_count": null,
380 | "outputs": []
381 | },
382 | {
383 | "cell_type": "code",
384 | "metadata": {
385 | "id": "thdiRvGDrJhy"
386 | },
387 | "source": [
388 | "# Load the trained Reformer in 'predict' mode\n",
389 | "model = trax.models.ReformerLM(mode='predict')\n",
390 | "output_dir = os.path.expanduser('model')\n",
391 | "model.init_from_file(os.path.join(output_dir,'model.pkl.gz'),\n",
392 | " weights_only=True)\n",
393 | "\n",
394 | "# Sample from ReformerLM\n",
395 | "output_token_ids = trax.supervised.decoding.autoregressive_sample(\n",
396 | " model, temperature=0.8, max_length=1024, accelerate=True)\n",
397 | "\n",
398 | "# Decode token IDs\n",
399 | "# Reformer outputed a batch with one item so access it using [0]\n",
400 | "# tolist() converts from int64 to int, the type SentencePiece expects\n",
401 | "input = TOKENIZER.DecodeIds(output_token_ids[0].tolist())"
402 | ],
403 | "execution_count": null,
404 | "outputs": []
405 | },
406 | {
407 | "cell_type": "code",
408 | "metadata": {
409 | "id": "Ox03iX3KHCKa"
410 | },
411 | "source": [
412 | "# Run the cells below to convert generated output to MIDI.\r\n",
413 | "# If you getting errors/halts, regenerate the output again.\r\n",
414 | "# Model must be sufficiently trained. Rec. 0.90+ accuracy for the output to make sense and pass error control.\r\n",
415 | "\r\n",
416 | "TXT = TMIDI.Tegridy_INT_String_to_TXT_Converter(input, line_by_line_input=False)"
417 | ],
418 | "execution_count": null,
419 | "outputs": []
420 | },
421 | {
422 | "cell_type": "code",
423 | "metadata": {
424 | "id": "WggjV2NNHCti"
425 | },
426 | "source": [
427 | "SONG = TMIDI.Tegridy_Reduced_TXT_to_Notes_Converter(TXT, has_MIDI_channels=False, has_velocities=False)"
428 | ],
429 | "execution_count": null,
430 | "outputs": []
431 | },
432 | {
433 | "cell_type": "code",
434 | "metadata": {
435 | "id": "z0MvzNCOHEXZ"
436 | },
437 | "source": [
438 | "stats = TMIDI.Tegridy_SONG_to_MIDI_Converter(SONG=SONG[0], output_file_name='/content/OUTPUT_MIDI')"
439 | ],
440 | "execution_count": null,
441 | "outputs": []
442 | }
443 | ]
444 | }
--------------------------------------------------------------------------------
/Super_Chamber_Piano.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "kernelspec": {
6 | "display_name": "Python 3",
7 | "language": "python",
8 | "name": "python3"
9 | },
10 | "language_info": {
11 | "codemirror_mode": {
12 | "name": "ipython",
13 | "version": 3
14 | },
15 | "file_extension": ".py",
16 | "mimetype": "text/x-python",
17 | "name": "python",
18 | "nbconvert_exporter": "python",
19 | "pygments_lexer": "ipython3",
20 | "version": "3.6.5"
21 | },
22 | "colab": {
23 | "name": "[Ver 2.0] Super Chamber Piano.ipynb",
24 | "provenance": [],
25 | "private_outputs": true,
26 | "collapsed_sections": [],
27 | "toc_visible": true,
28 | "include_colab_link": true
29 | },
30 | "accelerator": "GPU"
31 | },
32 | "cells": [
33 | {
34 | "cell_type": "markdown",
35 | "metadata": {
36 | "id": "view-in-github",
37 | "colab_type": "text"
38 | },
39 | "source": [
40 | "
"
41 | ]
42 | },
43 | {
44 | "cell_type": "markdown",
45 | "metadata": {
46 | "id": "HIqS2usIWHeI"
47 | },
48 | "source": [
49 | "# Super Chamber Piano (Ver 2.0): Notewise Music NN\n",
50 | "\n",
51 | "***\n",
52 | "\n",
53 | "## A Mini Musical Neural Net"
54 | ]
55 | },
56 | {
57 | "cell_type": "markdown",
58 | "metadata": {
59 | "id": "J5SX5WuiWThz"
60 | },
61 | "source": [
62 | "***\n",
63 | "\n",
64 | "All thanks and credit for this beautiful colab go out to edtky of GitHub on whose repo and code it is based: https://github.com/edtky/mini-musical-neural-net\n",
65 | "\n",
66 | "***\n",
67 | "\n"
68 | ]
69 | },
70 | {
71 | "cell_type": "markdown",
72 | "metadata": {
73 | "id": "ML_w70Rcod6f"
74 | },
75 | "source": [
76 | "# Model Specs and Default Parameters\n",
77 | "\n",
78 | "## 2 Layers LSTM\n",
79 | "\n",
80 | "### Hyperparameters\n",
81 | "\n",
82 | "1. sequence_len / n_word = 512 (previous: 128)\n",
83 | "2. batch_size / n_seq = 128\n",
84 | "3. hidden_dim = 512\n",
85 | "4. top_k words = 3 (previous: 5)\n",
86 | "5. predict seq_len = 512 (previous: 1024)\n",
87 | "6. epoch = 300\n",
88 | "\n",
89 | "***"
90 | ]
91 | },
92 | {
93 | "cell_type": "markdown",
94 | "metadata": {
95 | "id": "isGj8yhe0DvT"
96 | },
97 | "source": [
98 | "# System setup"
99 | ]
100 | },
101 | {
102 | "cell_type": "code",
103 | "metadata": {
104 | "id": "FVrjMED_5sCO",
105 | "cellView": "form"
106 | },
107 | "source": [
108 | "#@title Install dependencies\n",
109 | "!pip install pyknon\n",
110 | "!pip install pretty_midi\n",
111 | "!pip install pypianoroll\n",
112 | "!pip install mir_eval\n",
113 | "!apt install fluidsynth #Pip does not work for some reason. Only apt works\n",
114 | "!pip install midi2audio\n",
115 | "!git clone https://github.com/asigalov61/arc-diagrams\n",
116 | "!cp /usr/share/sounds/sf2/FluidR3_GM.sf2 /content/font.sf2"
117 | ],
118 | "execution_count": null,
119 | "outputs": []
120 | },
121 | {
122 | "cell_type": "markdown",
123 | "metadata": {
124 | "id": "sZajWNtE0Hwr"
125 | },
126 | "source": [
127 | "# Setup modules, functions, variables, and GPU check"
128 | ]
129 | },
130 | {
131 | "cell_type": "code",
132 | "metadata": {
133 | "id": "Sj9Af0iFod6g",
134 | "cellView": "form"
135 | },
136 | "source": [
137 | "#@title Load all modules, check the available devices (GPU/CPU), and setup MIDI parameters\n",
138 | "import numpy as np\n",
139 | "\n",
140 | "import torch\n",
141 | "from torch import nn\n",
142 | "from torch import optim\n",
143 | "import torch.nn.functional as F\n",
144 | "\n",
145 | "import keras\n",
146 | "from keras.utils import to_categorical\n",
147 | "\n",
148 | "import time\n",
149 | "\n",
150 | "import pretty_midi\n",
151 | "from midi2audio import FluidSynth\n",
152 | "from google.colab import output\n",
153 | "from IPython.display import display, Javascript, HTML, Audio\n",
154 | "\n",
155 | "import librosa\n",
156 | "import numpy as np\n",
157 | "import pretty_midi\n",
158 | "import pypianoroll\n",
159 | "from pypianoroll import Multitrack, Track\n",
160 | "import matplotlib\n",
161 | "import matplotlib.pyplot as plt\n",
162 | "#matplotlib.use('SVG')\n",
163 | "# For plotting\n",
164 | "import mir_eval.display\n",
165 | "import librosa.display\n",
166 | "%matplotlib inline\n",
167 | "\n",
168 | "\n",
169 | "from mido import MidiFile\n",
170 | "%cd /content/arc-diagrams/\n",
171 | "from arc_diagram import plot_arc_diagram\n",
172 | "\n",
173 | "\n",
174 | "dtype = torch.float\n",
175 | "device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n",
176 | "# Assume that we are on a CUDA machine, then this should print a CUDA device:\n",
177 | "print('Available Device:', device)\n",
178 | "\n",
179 | "!mkdir /content/midis\n",
180 | "\n",
181 | "sample_freq_variable = 12 #@param {type:\"number\"}\n",
182 | "note_range_variable = 62 #@param {type:\"number\"}\n",
183 | "note_offset_variable = 33 #@param {type:\"number\"}\n",
184 | "number_of_instruments = 2 #@param {type:\"number\"}\n",
185 | "chamber_option = True #@param {type:\"boolean\"}\n",
186 | "\n",
187 | "%cd /content/"
188 | ],
189 | "execution_count": null,
190 | "outputs": []
191 | },
192 | {
193 | "cell_type": "markdown",
194 | "metadata": {
195 | "id": "SiNnwNj80UwP"
196 | },
197 | "source": [
198 | "# (OPTIONS)"
199 | ]
200 | },
201 | {
202 | "cell_type": "code",
203 | "metadata": {
204 | "id": "9EpQajTGqIKr",
205 | "cellView": "form"
206 | },
207 | "source": [
208 | "#@title (OPTION 1) Convert your own MIDIs to Notewise TXT DataSet (before running this cell, upload your MIDI DataSet to /content/midis folder)\n",
209 | "import tqdm.auto\n",
210 | "import argparse\n",
211 | "import random\n",
212 | "import os\n",
213 | "import numpy as np\n",
214 | "from math import floor\n",
215 | "from pyknon.genmidi import Midi\n",
216 | "from pyknon.music import NoteSeq, Note\n",
217 | "import music21\n",
218 | "from music21 import instrument, volume\n",
219 | "from music21 import midi as midiModule\n",
220 | "from pathlib import Path\n",
221 | "import glob, sys\n",
222 | "from music21 import converter, instrument\n",
223 | "%cd /content\n",
224 | "notes=[]\n",
225 | "InstrumentID=0\n",
226 | "folder = '/content/midis/*mid'\n",
227 | "for file in tqdm.auto.tqdm(glob.glob(folder)):\n",
228 | " filename = file[-53:]\n",
229 | " print(filename)\n",
230 | "\n",
231 | " # fname = \"../midi-files/mozart/sonat-3.mid\"\n",
232 | " fname = filename\n",
233 | "\n",
234 | " mf=music21.midi.MidiFile()\n",
235 | " mf.open(fname)\n",
236 | " mf.read()\n",
237 | " mf.close()\n",
238 | " midi_stream=music21.midi.translate.midiFileToStream(mf)\n",
239 | " midi_stream\n",
240 | "\n",
241 | "\n",
242 | "\n",
243 | " sample_freq=sample_freq_variable\n",
244 | " note_range=note_range_variable\n",
245 | " note_offset=note_offset_variable\n",
246 | " chamber=chamber_option\n",
247 | " numInstruments=number_of_instruments\n",
248 | "\n",
249 | " s = midi_stream\n",
250 | " #print(s.duration.quarterLength)\n",
251 | "\n",
252 | " s[0].elements\n",
253 | "\n",
254 | "\n",
255 | " maxTimeStep = floor(s.duration.quarterLength * sample_freq)+1\n",
256 | " score_arr = np.zeros((maxTimeStep, numInstruments, note_range))\n",
257 | "\n",
258 | " #print(maxTimeStep, \"\\n\", score_arr.shape)\n",
259 | "\n",
260 | " # define two types of filters because notes and chords have different structures for storing their data\n",
261 | " # chord have an extra layer because it consist of multiple notes\n",
262 | "\n",
263 | " noteFilter=music21.stream.filters.ClassFilter('Note')\n",
264 | " chordFilter=music21.stream.filters.ClassFilter('Chord')\n",
265 | " \n",
266 | "\n",
267 | " # pitch.midi-note_offset: pitch is the numerical representation of a note. \n",
268 | " # note_offset is the the pitch relative to a zero mark. eg. B-=25, C=27, A=24\n",
269 | "\n",
270 | " # n.offset: the timestamps of each note, relative to the start of the score\n",
271 | " # by multiplying with the sample_freq, you make all the timestamps integers\n",
272 | "\n",
273 | " # n.duration.quarterLength: the duration of that note as a float eg. quarter note = 0.25, half note = 0.5\n",
274 | " # multiply by sample_freq to represent duration in terms of timesteps\n",
275 | "\n",
276 | " notes = []\n",
277 | " instrumentID = 0\n",
278 | " parts = instrument.partitionByInstrument(s)\n",
279 | " for i in range(len(parts.parts)): \n",
280 | " instru = parts.parts[i].getInstrument()\n",
281 | " \n",
282 | "\n",
283 | " for n in s.recurse().addFilter(noteFilter):\n",
284 | " if chamber:\n",
285 | " # assign_instrument where 0 means piano-like and 1 means violin-like, and -1 means neither\n",
286 | " if instru.instrumentName == 'Violin':\n",
287 | " notes.append((n.pitch.midi-note_offset, floor(n.offset*sample_freq), \n",
288 | " floor(n.duration.quarterLength*sample_freq), 1))\n",
289 | " \n",
290 | " notes.append((n.pitch.midi-note_offset, floor(n.offset*sample_freq), \n",
291 | " floor(n.duration.quarterLength*sample_freq), 0))\n",
292 | " \n",
293 | " #print(len(notes))\n",
294 | " notes[-5:]\n",
295 | "\n",
296 | " # do the same using a chord filter\n",
297 | "\n",
298 | " for c in s.recurse().addFilter(chordFilter):\n",
299 | " # unlike the noteFilter, this line of code is necessary as there are multiple notes in each chord\n",
300 | " # pitchesInChord is a list of notes at each chord eg. (, )\n",
301 | " pitchesInChord=c.pitches\n",
302 | " \n",
303 | " # do same as noteFilter and append all notes to the notes list\n",
304 | " for p in pitchesInChord:\n",
305 | " notes.append((p.midi-note_offset, floor(c.offset*sample_freq), \n",
306 | " floor(c.duration.quarterLength*sample_freq), 1))\n",
307 | "\n",
308 | " # do same as noteFilter and append all notes to the notes list\n",
309 | " for p in pitchesInChord:\n",
310 | " notes.append((p.midi-note_offset, floor(c.offset*sample_freq), \n",
311 | " floor(c.duration.quarterLength*sample_freq), 0))\n",
312 | " #print(len(notes))\n",
313 | " notes[-5:]\n",
314 | "\n",
315 | " # the variable/list \"notes\" is a collection of all the notes in the song, not ordered in any significant way\n",
316 | "\n",
317 | " for n in notes:\n",
318 | " \n",
319 | " # pitch is the first variable in n, previously obtained by n.midi-note_offset\n",
320 | " pitch=n[0]\n",
321 | " \n",
322 | " # do some calibration for notes that fall our of note range\n",
323 | " # i.e. less than 0 or more than note_range\n",
324 | " while pitch<0:\n",
325 | " pitch+=12\n",
326 | " while pitch>=note_range:\n",
327 | " pitch-=12\n",
328 | " \n",
329 | " # 3rd element refers to instrument type => if instrument is violin, use different pitch calibration\n",
330 | " if n[3]==1: #Violin lowest note is v22\n",
331 | " while pitch<22:\n",
332 | " pitch+=12\n",
333 | "\n",
334 | " # start building the 3D-tensor of shape: (796, 1, 38)\n",
335 | " # score_arr[0] = timestep\n",
336 | " # score_arr[1] = type of instrument\n",
337 | " # score_arr[2] = pitch/note out of the range of note eg. 38\n",
338 | " \n",
339 | " # n[0] = pitch\n",
340 | " # n[1] = timestep\n",
341 | " # n[2] = duration\n",
342 | " # n[3] = instrument\n",
343 | " #print(n[3])\n",
344 | " try:\n",
345 | " score_arr[n[1], n[3], pitch]=1 # Strike note\n",
346 | " score_arr[n[1]+1:n[1]+n[2], n[3], pitch]=2 # Continue holding note\n",
347 | " except:\n",
348 | " continue\n",
349 | "\n",
350 | " #print(score_arr.shape)\n",
351 | " # print first 5 timesteps\n",
352 | " score_arr[:5,0,]\n",
353 | "\n",
354 | "\n",
355 | " for timestep in score_arr:\n",
356 | " #print(list(reversed(range(len(timestep)))))\n",
357 | " break\n",
358 | "\n",
359 | " instr={}\n",
360 | " instr[0]=\"p\"\n",
361 | " instr[1]=\"v\"\n",
362 | "\n",
363 | " score_string_arr=[]\n",
364 | "\n",
365 | " # loop through all timesteps\n",
366 | " for timestep in score_arr:\n",
367 | " \n",
368 | " # selecting the instruments: i=0 means piano and i=1 means violin\n",
369 | " for i in list(reversed(range(len(timestep)))): # List violin note first, then piano note\n",
370 | " \n",
371 | " # \n",
372 | " score_string_arr.append(instr[i]+''.join([str(int(note)) for note in timestep[i]]))\n",
373 | "\n",
374 | " #print(type(score_string_arr), len(score_string_arr))\n",
375 | " score_string_arr[:5]\n",
376 | "\n",
377 | " modulated=[]\n",
378 | " # get the note range from the array\n",
379 | " note_range=len(score_string_arr[0])-1\n",
380 | "\n",
381 | " for i in range(0,12):\n",
382 | " for chord in score_string_arr:\n",
383 | " \n",
384 | " # minus the instrument letter eg. 'p'\n",
385 | " # add 6 zeros on each side of the string\n",
386 | " padded='000000'+chord[1:]+'000000'\n",
387 | " \n",
388 | " # add back the instrument letter eg. 'p'\n",
389 | " # append window of len=note_range back into \n",
390 | " # eg. if we have \"00012345000\"\n",
391 | " # iteratively, we want to get \"p00012\", \"p00123\", \"p01234\", \"p12345\", \"p23450\", \"p34500\", \"p45000\",\n",
392 | " modulated.append(chord[0]+padded[i:i+note_range])\n",
393 | "\n",
394 | " # 796 * 12\n",
395 | " #print(len(modulated))\n",
396 | " modulated[:5]\n",
397 | "\n",
398 | " # input of this function is a modulated string\n",
399 | " long_string = modulated\n",
400 | "\n",
401 | " translated_list=[]\n",
402 | "\n",
403 | " # for every timestep of the string\n",
404 | " for j in range(len(long_string)):\n",
405 | " \n",
406 | " # chord at timestep j eg. 'p00000000000000000000000000000000000100'\n",
407 | " chord=long_string[j]\n",
408 | " next_chord=\"\"\n",
409 | " \n",
410 | " # range is from next_timestep to max_timestep\n",
411 | " for k in range(j+1, len(long_string)):\n",
412 | " \n",
413 | " # checking if instrument of next chord is same as current chord\n",
414 | " if long_string[k][0]==chord[0]:\n",
415 | " \n",
416 | " # if same, set next chord as next element in modulation\n",
417 | " # otherwise, keep going until you find a chord with the same instrument\n",
418 | " # when you do, set it as the next chord\n",
419 | " next_chord=long_string[k]\n",
420 | " break\n",
421 | " \n",
422 | " # set prefix as the instrument\n",
423 | " # set chord and next_chord to be without the instrument prefix\n",
424 | " # next_chord is necessary to check when notes end\n",
425 | " prefix=chord[0]\n",
426 | " chord=chord[1:]\n",
427 | " next_chord=next_chord[1:]\n",
428 | " \n",
429 | " # checking for non-zero notes at one particular timestep\n",
430 | " # i is an integer indicating the index of each note the chord\n",
431 | " for i in range(len(chord)):\n",
432 | " \n",
433 | " if chord[i]==\"0\":\n",
434 | " continue\n",
435 | " \n",
436 | " # set note as 2 elements: instrument and index of note\n",
437 | " # examples: p22, p16, p4\n",
438 | " #p = music21.pitch.Pitch()\n",
439 | " #nt = music21.note.Note(p)\n",
440 | " #n.volume.velocity = 20\n",
441 | " #nt.volume.client == nt\n",
442 | " #V = nt.volume.velocity\n",
443 | " #print(V)\n",
444 | " #note=prefix+str(i)+' V' + str(V)\n",
445 | " note=prefix+str(i) \n",
446 | " \n",
447 | " # if note in chord is 1, then append the note eg. p22 to the list\n",
448 | " if chord[i]==\"1\":\n",
449 | " translated_list.append(note)\n",
450 | " \n",
451 | " # If chord[i]==\"2\" do nothing - we're continuing to hold the note\n",
452 | " \n",
453 | " # unless next_chord[i] is back to \"0\" and it's time to end the note.\n",
454 | " if next_chord==\"\" or next_chord[i]==\"0\": \n",
455 | " translated_list.append(\"end\"+note)\n",
456 | "\n",
457 | " # wait indicates end of every timestep\n",
458 | " if prefix==\"p\":\n",
459 | " translated_list.append(\"wait\")\n",
460 | "\n",
461 | " #print(len(translated_list))\n",
462 | " translated_list[:10]\n",
463 | "\n",
464 | " # this section transforms the list of notes into a string of notes\n",
465 | "\n",
466 | " # initialize i as zero and empty string\n",
467 | " i=0\n",
468 | " translated_string=\"\"\n",
469 | "\n",
470 | "\n",
471 | " while i \"wait2\"\n",
475 | " wait_count=1\n",
476 | " if translated_list[i]=='wait':\n",
477 | " while wait_count<=sample_freq*2 and i+wait_count\", \"\"]:\n",
1099 | " continue\n",
1100 | "\n",
1101 | " # if the event starts with 'end' indicating an end of note\n",
1102 | " elif score[i][:3]==\"end\":\n",
1103 | "\n",
1104 | " # if the event additionally ends with eoc, increare the time offset by 1\n",
1105 | " if score[i][-3:]==\"eoc\":\n",
1106 | " time_offset+=1\n",
1107 | " continue\n",
1108 | "\n",
1109 | " # if the event is wait, increase the timestamp by the number after the \"wait\"\n",
1110 | " elif score[i][:4]==\"wait\":\n",
1111 | " time_offset+=int(score[i][4:])\n",
1112 | " continue\n",
1113 | "\n",
1114 | " # in this block, we are looking for notes \n",
1115 | " else:\n",
1116 | " # Look ahead to see if an end was generated\n",
1117 | " # soon after. \n",
1118 | " duration=1\n",
1119 | " has_end=False\n",
1120 | " note_string_len = len(score[i])\n",
1121 | " for j in range(1,200):\n",
1122 | " if i+j==len(score):\n",
1123 | " break\n",
1124 | " if score[i+j][:4]==\"wait\":\n",
1125 | " duration+=int(score[i+j][4:])\n",
1126 | " if score[i+j][:3+note_string_len]==\"end\"+score[i] or score[i+j][:note_string_len]==score[i]:\n",
1127 | " has_end=True\n",
1128 | " break\n",
1129 | " if score[i+j][-3:]==\"eoc\":\n",
1130 | " duration+=1\n",
1131 | "\n",
1132 | " if not has_end:\n",
1133 | " duration=12\n",
1134 | "\n",
1135 | " add_wait = 0\n",
1136 | " if score[i][-3:]==\"eoc\":\n",
1137 | " score[i]=score[i][:-3]\n",
1138 | " add_wait = 1\n",
1139 | "\n",
1140 | " try: \n",
1141 | " new_note=music21.note.Note(int(score[i][1:])+note_offset) \n",
1142 | " new_note.duration = music21.duration.Duration(duration*speed)\n",
1143 | " new_note.offset=time_offset*speed\n",
1144 | " if score[i][0]==\"v\":\n",
1145 | " violin_notes.append(new_note)\n",
1146 | " else:\n",
1147 | " piano_notes.append(new_note) \n",
1148 | " except:\n",
1149 | " print(\"Unknown note: \" + score[i])\n",
1150 | "\n",
1151 | "\n",
1152 | "\n",
1153 | "\n",
1154 | " time_offset+=add_wait\n",
1155 | "\n",
1156 | " # list of all notes for each instrument should be ready at this stage\n",
1157 | "\n",
1158 | " # creating music21 instrument objects \n",
1159 | " \n",
1160 | " piano=music21.instrument.fromString(\"Piano\")\n",
1161 | " violin=music21.instrument.fromString(\"Violin\")\n",
1162 | "\n",
1163 | " # insert instrument object to start (0 index) of notes list\n",
1164 | " \n",
1165 | " piano_notes.insert(0, piano)\n",
1166 | " violin_notes.insert(0, violin)\n",
1167 | " # create music21 stream object for individual instruments\n",
1168 | " \n",
1169 | " piano_stream=music21.stream.Stream(piano_notes)\n",
1170 | " violin_stream=music21.stream.Stream(violin_notes)\n",
1171 | " # merge both stream objects into a single stream of 2 instruments\n",
1172 | " note_stream = music21.stream.Stream([piano_stream, violin_stream])\n",
1173 | "\n",
1174 | " \n",
1175 | " note_stream.write('midi', fp=\"/content/\"+filename[:-4]+\".mid\")\n",
1176 | " print(\"Done! Decoded midi file saved to 'content/'\")\n",
1177 | "\n",
1178 | " \n",
1179 | "decoder('output.txt')\n",
1180 | "from google.colab import files\n",
1181 | "files.download('/content/output.mid')"
1182 | ],
1183 | "execution_count": null,
1184 | "outputs": []
1185 | },
1186 | {
1187 | "cell_type": "code",
1188 | "metadata": {
1189 | "id": "OP-a6xhKp6NQ",
1190 | "cellView": "form"
1191 | },
1192 | "source": [
1193 | "#@title Plot, Graph, and Listen to the Output :)\n",
1194 | "graphs_length_inches = 18 #@param {type:\"slider\", min:0, max:20, step:1}\n",
1195 | "notes_graph_height = 6 #@param {type:\"slider\", min:0, max:20, step:1}\n",
1196 | "highest_displayed_pitch = 92 #@param {type:\"slider\", min:1, max:128, step:1}\n",
1197 | "lowest_displayed_pitch = 24 #@param {type:\"slider\", min:1, max:128, step:1}\n",
1198 | "\n",
1199 | "%cd /content/\n",
1200 | "\n",
1201 | "midi_data = pretty_midi.PrettyMIDI('/content/output.mid')\n",
1202 | "\n",
1203 | "def plot_piano_roll(pm, start_pitch, end_pitch, fs=100):\n",
1204 | " # Use librosa's specshow function for displaying the piano roll\n",
1205 | " librosa.display.specshow(pm.get_piano_roll(fs)[start_pitch:end_pitch],\n",
1206 | " hop_length=1, sr=fs, x_axis='time', y_axis='cqt_note',\n",
1207 | " fmin=pretty_midi.note_number_to_hz(start_pitch))\n",
1208 | "\n",
1209 | "\n",
1210 | "\n",
1211 | "roll = np.zeros([int(graphs_length_inches), 128])\n",
1212 | "# Plot the output\n",
1213 | "\n",
1214 | "track = Multitrack('/content/output.mid', name='track')\n",
1215 | "plt.figure(figsize=[graphs_length_inches, notes_graph_height])\n",
1216 | "fig, ax = track.plot()\n",
1217 | "fig.set_size_inches(graphs_length_inches, notes_graph_height)\n",
1218 | "plt.figure(figsize=[graphs_length_inches, notes_graph_height])\n",
1219 | "ax2 = plot_piano_roll(midi_data, int(lowest_displayed_pitch), int(highest_displayed_pitch))\n",
1220 | "plt.show(block=False)\n",
1221 | "\n",
1222 | "\n",
1223 | "FluidSynth(\"/content/font.sf2\", 16000).midi_to_audio('/content/output.mid', '/content/output.wav')\n",
1224 | "Audio('/content/output.wav', rate=16000)"
1225 | ],
1226 | "execution_count": null,
1227 | "outputs": []
1228 | },
1229 | {
1230 | "cell_type": "code",
1231 | "metadata": {
1232 | "id": "4ajJYg7RwqIk",
1233 | "cellView": "form"
1234 | },
1235 | "source": [
1236 | "#@title Reward yourself by making a nice Arc diagram from the generated output/MIDI file\n",
1237 | "%cd '/content/arc-diagrams'\n",
1238 | "\n",
1239 | "midi_file = '/content/output.mid'\n",
1240 | "plot_title = \"Super Chamber Piano Output Arc Diagram\"\n",
1241 | "\n",
1242 | "# midi_file = 'midis/fuer_elise.mid'\n",
1243 | "# plot_title = \"Für Elise (Beethoven)\"\n",
1244 | "\n",
1245 | "\n",
1246 | "def stringify_notes(midi_file, track_number ):\n",
1247 | "\n",
1248 | " mid = MidiFile(midi_file)\n",
1249 | " track_notes = {}\n",
1250 | " for i, track in enumerate(mid.tracks):\n",
1251 | " track_notes[i] = ''\n",
1252 | " for msg in track:\n",
1253 | " if( msg.type == 'note_on'):\n",
1254 | " track_notes[i] += str(msg.note) +'n'\n",
1255 | " if( msg.type == 'note_off'):\n",
1256 | " track_notes[i] += str(msg.note) +'f'\n",
1257 | " return track_notes[track_number] \n",
1258 | "try:\n",
1259 | " plot_arc_diagram(stringify_notes(midi_file, 0), plot_title)\n",
1260 | " from google.colab import files\n",
1261 | " files.download('/content/arc-diagrams/output.png')\n",
1262 | "except:\n",
1263 | " print('Could not plot the diagram. Try again/another composition.')\n",
1264 | "\n"
1265 | ],
1266 | "execution_count": null,
1267 | "outputs": []
1268 | },
1269 | {
1270 | "cell_type": "markdown",
1271 | "metadata": {
1272 | "id": "XhNSpt7AzYsV"
1273 | },
1274 | "source": [
1275 | "# Save what you want to Google Drive (standard GD connect code)"
1276 | ]
1277 | },
1278 | {
1279 | "cell_type": "code",
1280 | "metadata": {
1281 | "id": "3m-LweGaY3a1"
1282 | },
1283 | "source": [
1284 | "from google.colab import drive\n",
1285 | "drive.mount('/content/drive')"
1286 | ],
1287 | "execution_count": null,
1288 | "outputs": []
1289 | }
1290 | ]
1291 | }
--------------------------------------------------------------------------------
/Super_Piano_2.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "Super-Piano-2.ipynb",
7 | "provenance": [],
8 | "collapsed_sections": [],
9 | "toc_visible": true,
10 | "machine_shape": "hm",
11 | "mount_file_id": "1blMgPtY7OQr2h4HaZCtmYzzbrVFhNaGo",
12 | "authorship_tag": "ABX9TyO4juPgoId9vSJn9odbIZe3",
13 | "include_colab_link": true
14 | },
15 | "kernelspec": {
16 | "name": "python3",
17 | "display_name": "Python 3"
18 | },
19 | "accelerator": "GPU"
20 | },
21 | "cells": [
22 | {
23 | "cell_type": "markdown",
24 | "metadata": {
25 | "id": "view-in-github",
26 | "colab_type": "text"
27 | },
28 | "source": [
29 | "
"
30 | ]
31 | },
32 | {
33 | "cell_type": "markdown",
34 | "metadata": {
35 | "id": "avfslsXnDS4j",
36 | "colab_type": "text"
37 | },
38 | "source": [
39 | "#Super Piano 2\n",
40 | "\n",
41 | "MAKE YOUR OWN SOTA PIANO MUSIC AI MODEL IN UNDER 4 HOURS !!! :)\n",
42 | "\n",
43 | "Based on Yuankui Lee's repo and code https://github.com/djosix/Performance-RNN-PyTorch\n",
44 | "\n",
45 | "MAESTRO Dataset is courtesy of Google Magenta Team and it is distributed under Attribution-NonCommercial-ShareAlike 4.0 International license.\n",
46 | "\n",
47 | "So keep this in mind and respect everyone's copyright, please :)\n",
48 | "\n",
49 | "Huge thanks go out to all people who shared these amazing code contributions and made this Colab notebook possible :) Thank you so much, guys!"
50 | ]
51 | },
52 | {
53 | "cell_type": "markdown",
54 | "metadata": {
55 | "id": "bHWiJvW4vmGM",
56 | "colab_type": "text"
57 | },
58 | "source": [
59 | "## Setup the environment"
60 | ]
61 | },
62 | {
63 | "cell_type": "code",
64 | "metadata": {
65 | "id": "i2Zz7WiBy9qC",
66 | "colab_type": "code",
67 | "cellView": "form",
68 | "colab": {}
69 | },
70 | "source": [
71 | "#@title Install all dependencies and requrements\n",
72 | "print('3..2..1..lets do it')\n",
73 | "!pip install torch==1.6.0+cu101 torchvision==0.7.0+cu101 -f https://download.pytorch.org/whl/torch_stable.html\n",
74 | "!pip install numpy\n",
75 | "%tensorflow_version 1.x\n",
76 | "!pip install tensorflow-gpu==1.15.3\n",
77 | "import os\n",
78 | "os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"0\" \n",
79 | "import tensorflow as tf\n",
80 | "!pip install tensorboard\n",
81 | "!pip install progress\n",
82 | "!pip install pretty-midi\n",
83 | "!pip install pypianoroll\n",
84 | "!pip install matplotlib\n",
85 | "!pip install mir_eval\n",
86 | "!pip install librosa\n",
87 | "!pip install pyFluidSynth\n",
88 | "!apt install fluidsynth #Pip does not work for some reason. Only apt works\n",
89 | "!pip install midi2audio\n",
90 | "!git clone https://github.com/asigalov61/Performance-RNN-PyTorch\n",
91 | "!cp /usr/share/sounds/sf2/FluidR3_GM.sf2 /content/font.sf2\n",
92 | "from midi2audio import FluidSynth\n",
93 | "from google.colab import output\n",
94 | "from IPython.display import display, Javascript, HTML, Audio\n",
95 | "!nvidia-smi\n",
96 | "print('Success :) Everything is installed and should work fine :) Enjoy!')"
97 | ],
98 | "execution_count": null,
99 | "outputs": []
100 | },
101 | {
102 | "cell_type": "markdown",
103 | "metadata": {
104 | "id": "Jv25m6-Xuzlu",
105 | "colab_type": "text"
106 | },
107 | "source": [
108 | "### Download and Unzip training MIDIs DataSet"
109 | ]
110 | },
111 | {
112 | "cell_type": "code",
113 | "metadata": {
114 | "id": "uvcch3KePuCq",
115 | "colab_type": "code",
116 | "cellView": "form",
117 | "colab": {}
118 | },
119 | "source": [
120 | "#@title (Best Choice/Works best stand-alone) Super Piano 2 Performance DataSet 320 MIDIs \n",
121 | "%cd /content/Performance-RNN-PyTorch/dataset/midi\n",
122 | "!wget 'https://github.com/asigalov61/AlexMIDIDataSet/raw/master/Super-Piano-2-Performance-DataSet-CC-BY-NC-SA.zip'\n",
123 | "!unzip -j 'Super-Piano-2-Performance-DataSet-CC-BY-NC-SA.zip'\n",
124 | "!rm 'Super-Piano-2-Performance-DataSet-CC-BY-NC-SA.zip'"
125 | ],
126 | "execution_count": null,
127 | "outputs": []
128 | },
129 | {
130 | "cell_type": "markdown",
131 | "metadata": {
132 | "id": "yLOHEIgemfRD",
133 | "colab_type": "text"
134 | },
135 | "source": [
136 | "###(Optional) Download the pre-trained model to generate music without training"
137 | ]
138 | },
139 | {
140 | "cell_type": "code",
141 | "metadata": {
142 | "id": "QMC1hNL6mukM",
143 | "colab_type": "code",
144 | "cellView": "form",
145 | "colab": {}
146 | },
147 | "source": [
148 | "#@title Super Piano 2 Pre-Trained Performance Model (floss=1.05 - 4k training steps)\n",
149 | "%cd /content/Performance-RNN-PyTorch/save\n",
150 | "!wget 'https://superpiano.s3-us-west-1.amazonaws.com/myModel.sess'\n",
151 | "%cd /content/Performance-RNN-PyTorch"
152 | ],
153 | "execution_count": null,
154 | "outputs": []
155 | },
156 | {
157 | "cell_type": "markdown",
158 | "metadata": {
159 | "id": "Dj4PwQitvSVa",
160 | "colab_type": "text"
161 | },
162 | "source": [
163 | "### Prepare and pre-process your MIDI DataSet for training"
164 | ]
165 | },
166 | {
167 | "cell_type": "code",
168 | "metadata": {
169 | "id": "L1q2Xa900PuZ",
170 | "colab_type": "code",
171 | "cellView": "form",
172 | "colab": {}
173 | },
174 | "source": [
175 | "#@title This may take a while, especially on the large DataSets, so please be patient\n",
176 | "number_of_parallel_threads = 64 #@param {type:\"slider\", min:1, max:64, step:1}\n",
177 | "%cd /content/Performance-RNN-PyTorch\n",
178 | "!python3 preprocess.py '/content/Performance-RNN-PyTorch/dataset/midi' '/content/Performance-RNN-PyTorch/dataset/processed' $number_of_parallel_threads"
179 | ],
180 | "execution_count": null,
181 | "outputs": []
182 | },
183 | {
184 | "cell_type": "markdown",
185 | "metadata": {
186 | "id": "mhnT38z_yuxp",
187 | "colab_type": "text"
188 | },
189 | "source": [
190 | "### (Optional) Activate Tensorboard to monitor the progress of the model during training. You can also activate this cell at any other time to view logs/records of all training runs"
191 | ]
192 | },
193 | {
194 | "cell_type": "code",
195 | "metadata": {
196 | "id": "oGLZ_Gh4v63C",
197 | "colab_type": "code",
198 | "cellView": "form",
199 | "colab": {}
200 | },
201 | "source": [
202 | "#@title Tensorboard Graphs and Stats\n",
203 | "# Load the TensorBoard notebook extension\n",
204 | "%reload_ext tensorboard\n",
205 | "import tensorflow as tf\n",
206 | "import datetime, os\n",
207 | "%tensorboard --logdir /content/Performance-RNN-PyTorch/runs"
208 | ],
209 | "execution_count": null,
210 | "outputs": []
211 | },
212 | {
213 | "cell_type": "markdown",
214 | "metadata": {
215 | "id": "zLQcmGNdzfZi",
216 | "colab_type": "text"
217 | },
218 | "source": [
219 | "###Train your model quickly here :) \n",
220 | "\n",
221 | "WARNING: Created/resulting Model may produce (partially) plagiarized (overfitted) output. Excercise care and respect the copyright, please :) NOTE: You can manipulate provided variables below to further influence/improve generated output. Only the first batch is downloaded and plotted."
222 | ]
223 | },
224 | {
225 | "cell_type": "code",
226 | "metadata": {
227 | "id": "f1l-9hW92vJX",
228 | "colab_type": "code",
229 | "cellView": "form",
230 | "colab": {}
231 | },
232 | "source": [
233 | "#@title Main Training Loop\n",
234 | "\n",
235 | "number_of_batches = 384 #@param {type:\"slider\", min:1, max:512, step:1}\n",
236 | "window_size = 256 #@param {type:\"slider\", min:0, max:512, step:8}\n",
237 | "stride_size = 30 #@param {type:\"slider\", min:1, max:30, step:1}\n",
238 | "hidden_dimension_size = 1024 #@param {type:\"number\"}\n",
239 | "learning_rate = 0.001 #@param {type:\"number\"}\n",
240 | "control_ratio = 0.9#@param {type:\"number\"}\n",
241 | "teacher_forcing_ratio = 0.9 #@param {type:\"number\"}\n",
242 | "save_model_every = 10\n",
243 | "\n",
244 | "\n",
245 | "%cd /content/Performance-RNN-PyTorch\n",
246 | "!python3 train.py -s save/myModel.sess -d '/content/Performance-RNN-PyTorch/dataset/processed' -b $number_of_batches -w $window_size -c $control_ratio -T $teacher_forcing_ratio -t -L -p hidden_dim=$hidden_dimension_size -l $learning_rate -S $stride_size"
247 | ],
248 | "execution_count": null,
249 | "outputs": []
250 | },
251 | {
252 | "cell_type": "markdown",
253 | "metadata": {
254 | "id": "-WSwGrMs2qNe",
255 | "colab_type": "text"
256 | },
257 | "source": [
258 | "###Generate, Plot, Graph, Save, Download, and Render the resulting output"
259 | ]
260 | },
261 | {
262 | "cell_type": "markdown",
263 | "metadata": {
264 | "id": "5nQKPp51If-V",
265 | "colab_type": "text"
266 | },
267 | "source": [
268 | "NOTES: Control option -c takes commands or a processed .data file path.\n",
269 | "E.g., \"PITCH_HISTOGRAM;NOTE_DENSITY\" like -c \"2,0,1,1,0,1,0,1,1,0,0,1;4\", or \";3\" which gives all pitches the same probability or a /path/to/processed/midi/file.data\" to use the specific control sequence from the given processed data file. Option -S stands for Stochastic Beam Search Option"
270 | ]
271 | },
272 | {
273 | "cell_type": "markdown",
274 | "metadata": {
275 | "id": "6u0hx2NyoGn5",
276 | "colab_type": "text"
277 | },
278 | "source": [
279 | "A sample on C Major Scale \n",
280 | "control option: -c '1,0,1,0,1,1,0,1,0,1,0,1;4'\n",
281 | "\n",
282 | "A sample on C Minor Scale \n",
283 | "control option: -c '1,0,1,1,0,1,0,1,1,0,0,1;4'\n",
284 | "\n",
285 | "A sample on C Major Pentatonic Scale \n",
286 | "control option: -c '5,0,4,0,4,1,0,5,0,4,0,1;3'\n",
287 | "\n",
288 | "A sample on C Minor Pentatonic Scale \n",
289 | "control option: -c '5,0,1,4,0,4,0,5,1,0,4,0;3'"
290 | ]
291 | },
292 | {
293 | "cell_type": "code",
294 | "metadata": {
295 | "id": "lnA3aoTE8SjZ",
296 | "colab_type": "code",
297 | "cellView": "form",
298 | "colab": {}
299 | },
300 | "source": [
301 | "#@title\n",
302 | "number_of_tokens_to_generate = 4096 #@param {type:\"slider\", min:128, max:16384, step:128}\n",
303 | "model_temperature = 0.8 #@param {type:\"slider\", min:0, max:5, step:0.1}\n",
304 | "number_of_batches_and_files_to_generate = 1 #@param {type:\"slider\", min:1, max:32, step:1}\n",
305 | "full_model_path_and_file_name = \"/content/Performance-RNN-PyTorch/save/myModel.sess\" #@param {type:\"string\"}\n",
306 | "greedy_ratio = \"0\" #@param {type:\"string\"}\n",
307 | "generation_control_seed = \"\" #@param {type:\"string\"}\n",
308 | "extra_flags = \"\" #@param {type:\"string\"}\n",
309 | "\n",
310 | "%cd /content/Performance-RNN-PyTorch\n",
311 | "\n",
312 | "!python3 generate.py -l $number_of_tokens_to_generate -T $model_temperature -b $number_of_batches_and_files_to_generate -s $full_model_path_and_file_name -g $greedy_ratio $generation_control_seed $extra_flags\n",
313 | "\n",
314 | "print('Successfully exported the output to output-000.mid')\n",
315 | "\n",
316 | "from google.colab import files\n",
317 | "\n",
318 | "files.download('/content/Performance-RNN-PyTorch/output/output-000.mid')\n"
319 | ],
320 | "execution_count": null,
321 | "outputs": []
322 | },
323 | {
324 | "cell_type": "code",
325 | "metadata": {
326 | "id": "czxhLgcUzBWt",
327 | "colab_type": "code",
328 | "cellView": "form",
329 | "colab": {}
330 | },
331 | "source": [
332 | "#@title Plot and Graph the Output :) Only first batch MIDI file is plotted and displayed \n",
333 | "graphs_length_inches = 18 #@param {type:\"slider\", min:0, max:20, step:1}\n",
334 | "notes_graph_height = 6 #@param {type:\"slider\", min:0, max:20, step:1}\n",
335 | "highest_displayed_pitch = 100 #@param {type:\"slider\", min:1, max:128, step:1}\n",
336 | "lowest_displayed_pitch = 20 #@param {type:\"slider\", min:1, max:128, step:1}\n",
337 | "\n",
338 | "import librosa\n",
339 | "import numpy as np\n",
340 | "import pretty_midi\n",
341 | "import pypianoroll\n",
342 | "from pypianoroll import Multitrack, Track\n",
343 | "import matplotlib\n",
344 | "import matplotlib.pyplot as plt\n",
345 | "matplotlib.use('SVG')\n",
346 | "# For plotting\n",
347 | "import mir_eval.display\n",
348 | "import librosa.display\n",
349 | "%matplotlib inline\n",
350 | "\n",
351 | "\n",
352 | "midi_data = pretty_midi.PrettyMIDI('/content/Performance-RNN-PyTorch/output/output-000.mid')\n",
353 | "\n",
354 | "def plot_piano_roll(pm, start_pitch, end_pitch, fs=100):\n",
355 | " # Use librosa's specshow function for displaying the piano roll\n",
356 | " librosa.display.specshow(pm.get_piano_roll(fs)[start_pitch:end_pitch],\n",
357 | " hop_length=1, sr=fs, x_axis='time', y_axis='cqt_note',\n",
358 | " fmin=pretty_midi.note_number_to_hz(start_pitch))\n",
359 | "\n",
360 | "\n",
361 | "\n",
362 | "roll = np.zeros([int(graphs_length_inches), 128])\n",
363 | "# Plot the output\n",
364 | "\n",
365 | "track = Multitrack('/content/Performance-RNN-PyTorch/output/output-000.mid', name='track')\n",
366 | "plt.figure(figsize=[graphs_length_inches, notes_graph_height])\n",
367 | "fig, ax = track.plot()\n",
368 | "fig.set_size_inches(graphs_length_inches, notes_graph_height)\n",
369 | "plt.figure(figsize=[graphs_length_inches, notes_graph_height])\n",
370 | "ax2 = plot_piano_roll(midi_data, lowest_displayed_pitch, highest_displayed_pitch)\n",
371 | "plt.show(block=False)\n",
372 | "\n",
373 | "# Generate rendering (WAV)\n",
374 | "\n",
375 | "\n",
376 | "#audio = midi_data.Synthesize()\n",
377 | "\n",
378 | "#print(audio.shape)\n",
379 | "\n",
380 | "#plt.figure(figsize=[graphs_length_inches, rendered_wav_graph_height])\n",
381 | "#plt.plot(audio)\n",
382 | "#plt.show(block=False)\n",
383 | "\n",
384 | "#import IPython.display as ipd\n",
385 | "#ipd.Audio(audio, rate=16000)"
386 | ],
387 | "execution_count": null,
388 | "outputs": []
389 | },
390 | {
391 | "cell_type": "code",
392 | "metadata": {
393 | "id": "oHjK-8mm0Si6",
394 | "colab_type": "code",
395 | "colab": {},
396 | "cellView": "form"
397 | },
398 | "source": [
399 | "#@title Render first MIDI output file for playback (very slow on long compositions)\n",
400 | "FluidSynth(\"/content/font.sf2\", sample_rate=16000).midi_to_audio('/content/Performance-RNN-PyTorch/output/output-000.mid','output_wav.wav')\n",
401 | "\n",
402 | "# set the src and play\n",
403 | "Audio(\"output_wav.wav\", rate=16000)"
404 | ],
405 | "execution_count": null,
406 | "outputs": []
407 | },
408 | {
409 | "cell_type": "markdown",
410 | "metadata": {
411 | "id": "XqvVYDWFcYPN",
412 | "colab_type": "text"
413 | },
414 | "source": [
415 | "###BONUS: Super Plots and Graphs of the Generated Output (Enjoy :)"
416 | ]
417 | },
418 | {
419 | "cell_type": "code",
420 | "metadata": {
421 | "id": "PMG8-s2zSgZ9",
422 | "colab_type": "code",
423 | "cellView": "form",
424 | "colab": {}
425 | },
426 | "source": [
427 | "#@title Music21 Graphs\n",
428 | "import music21\n",
429 | "from music21 import *\n",
430 | "\n",
431 | "s = converter.parse(\"/content/Performance-RNN-PyTorch/output/output-000.mid\")\n",
432 | "\n",
433 | "p = music21.graph.plot.HistogramPitchSpace(s)\n",
434 | "p.id\n",
435 | "'histogram-pitchSpace-count'\n",
436 | "p.run() # with defaults and proper configuration, will open graph\n",
437 | "\n",
438 | "p = graph.plot.HistogramPitchClass(s)\n",
439 | "p.id\n",
440 | "'histogram-pitchClass-count'\n",
441 | "p.run()\n",
442 | "\n",
443 | "p = graph.plot.WindowedKey(s.parts[0])\n",
444 | "p.run() \n",
445 | "p = graph.plot.ScatterPitchSpaceQuarterLength(s)\n",
446 | "p.id\n",
447 | "'scatter-quarterLength-pitchSpace'\n",
448 | "p.run()\n",
449 | "\n",
450 | "p = graph.plot.Plot3DBarsPitchSpaceQuarterLength(s)\n",
451 | "p.id\n",
452 | "'3DBars-quarterLength-pitchSpace-count'\n",
453 | "p.run()"
454 | ],
455 | "execution_count": null,
456 | "outputs": []
457 | }
458 | ]
459 | }
--------------------------------------------------------------------------------
/Super_Piano_3.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "Super_Piano_3.ipynb",
7 | "provenance": [],
8 | "collapsed_sections": [],
9 | "machine_shape": "hm",
10 | "include_colab_link": true
11 | },
12 | "kernelspec": {
13 | "name": "python3",
14 | "display_name": "Python 3"
15 | },
16 | "accelerator": "GPU"
17 | },
18 | "cells": [
19 | {
20 | "cell_type": "markdown",
21 | "metadata": {
22 | "id": "view-in-github",
23 | "colab_type": "text"
24 | },
25 | "source": [
26 | "
"
27 | ]
28 | },
29 | {
30 | "cell_type": "markdown",
31 | "metadata": {
32 | "id": "9opKSK2RSDRg",
33 | "colab_type": "text"
34 | },
35 | "source": [
36 | "# Super Piano 3: Google Music Transformer\n",
37 | "## Generating Music with Long-Term structure\n",
38 | "### Based on 2019 ICLR paper by Cheng-Zhi Anna Huang, Google Brain and Damon Gwinn's code/repo https://github.com/gwinndr/MusicTransformer-Pytorch\n",
39 | "\n",
40 | "Huge thanks go out to the following people who contributed the code/repos used in this colab. Additional contributors are listed in the code as well.\n",
41 | "\n",
42 | "1) Kevin-Yang https://github.com/jason9693/midi-neural-processor\n",
43 | "\n",
44 | "2) gudgud96 for fixing Kevin's MIDI Encoder properly https://github.com/gudgud96\n",
45 | "\n",
46 | "2) jinyi12, Zac Koh, Akamight, Zhang https://github.com/COMP6248-Reproducability-Challenge/music-transformer-comp6248\n",
47 | "\n",
48 | "Thank you so much for your hard work and for sharing it with the world :)\n"
49 | ]
50 | },
51 | {
52 | "cell_type": "markdown",
53 | "metadata": {
54 | "id": "05hD19W0hSCP",
55 | "colab_type": "text"
56 | },
57 | "source": [
58 | "###Setup Environment and Dependencies. Check GPU."
59 | ]
60 | },
61 | {
62 | "cell_type": "code",
63 | "metadata": {
64 | "id": "Ror_UJUp7wlO",
65 | "colab_type": "code",
66 | "cellView": "form",
67 | "colab": {}
68 | },
69 | "source": [
70 | "#@title Check if GPU (driver) is avaiiable (you do not want to run this on CPU, trust me)\n",
71 | "!nvcc --version\n",
72 | "!nvidia-smi"
73 | ],
74 | "execution_count": null,
75 | "outputs": []
76 | },
77 | {
78 | "cell_type": "code",
79 | "metadata": {
80 | "id": "paYvoZHihtux",
81 | "colab_type": "code",
82 | "cellView": "form",
83 | "colab": {}
84 | },
85 | "source": [
86 | "#@title Clone/Install all dependencies\n",
87 | "!git clone https://github.com/asigalov61/midi-neural-processor\n",
88 | "!git clone https://github.com/asigalov61/MusicTransformer-Pytorch\n",
89 | "!pip install tqdm\n",
90 | "!pip install progress\n",
91 | "!pip install pretty-midi\n",
92 | "!pip install pypianoroll\n",
93 | "!pip install matplotlib\n",
94 | "!pip install librosa\n",
95 | "!pip install scipy\n",
96 | "!pip install pillow\n",
97 | "!apt install fluidsynth #Pip does not work for some reason. Only apt works\n",
98 | "!pip install midi2audio\n",
99 | "!pip install mir_eval\n",
100 | "!cp /usr/share/sounds/sf2/FluidR3_GM.sf2 /content/font.sf2"
101 | ],
102 | "execution_count": null,
103 | "outputs": []
104 | },
105 | {
106 | "cell_type": "code",
107 | "metadata": {
108 | "id": "VM71tUPVfffi",
109 | "colab_type": "code",
110 | "cellView": "form",
111 | "colab": {}
112 | },
113 | "source": [
114 | "#@title Import all needed modules\n",
115 | "import numpy as np\n",
116 | "import pickle\n",
117 | "import os\n",
118 | "import sys\n",
119 | "import math\n",
120 | "import random\n",
121 | "# For plotting\n",
122 | "import pypianoroll\n",
123 | "from pypianoroll import Multitrack, Track\n",
124 | "import matplotlib\n",
125 | "import matplotlib.pyplot as plt\n",
126 | "#matplotlib.use('SVG')\n",
127 | "#%matplotlib inline\n",
128 | "#matplotlib.get_backend()\n",
129 | "import mir_eval.display\n",
130 | "import librosa\n",
131 | "import librosa.display\n",
132 | "# For rendering output audio\n",
133 | "import pretty_midi\n",
134 | "from midi2audio import FluidSynth\n",
135 | "from google.colab import output\n",
136 | "from IPython.display import display, Javascript, HTML, Audio"
137 | ],
138 | "execution_count": null,
139 | "outputs": []
140 | },
141 | {
142 | "cell_type": "code",
143 | "metadata": {
144 | "id": "34spqHYPJtTJ",
145 | "colab_type": "code",
146 | "cellView": "form",
147 | "colab": {}
148 | },
149 | "source": [
150 | "#@title (Optional) Pre-trained models download (2 models trained for 100 epochs to 1.968 FLoss and 0.420 acc)\n",
151 | "!mkdir /content/MusicTransformer-Pytorch/rpr\n",
152 | "!mkdir /content/MusicTransformer-Pytorch/rpr/results\n",
153 | "%cd /content/MusicTransformer-Pytorch/rpr/results\n",
154 | "!wget 'https://superpiano.s3-us-west-1.amazonaws.com/SuperPiano3models.zip'\n",
155 | "!unzip SuperPiano3models.zip\n",
156 | "%cd /content/MusicTransformer-Pytorch/"
157 | ],
158 | "execution_count": null,
159 | "outputs": []
160 | },
161 | {
162 | "cell_type": "markdown",
163 | "metadata": {
164 | "id": "4kE-VhygOPuG",
165 | "colab_type": "text"
166 | },
167 | "source": [
168 | "#Please note that you MUST DOWNLOAD AND PROCESS ONE OF THE DATASETS TO TRAIN OR TO USE PRE-TRAINED MODEL as it primes the model from DATASET files."
169 | ]
170 | },
171 | {
172 | "cell_type": "markdown",
173 | "metadata": {
174 | "id": "9gd-O5LZyJGD",
175 | "colab_type": "text"
176 | },
177 | "source": [
178 | "#Option 1: MAESTRO DataSet"
179 | ]
180 | },
181 | {
182 | "cell_type": "code",
183 | "metadata": {
184 | "id": "0bGqw8o6oxUY",
185 | "colab_type": "code",
186 | "cellView": "form",
187 | "colab": {}
188 | },
189 | "source": [
190 | "#@title Download Google Magenta MAESTRO v.2.0.0 Piano MIDI Dataset (~1300 MIDIs)\n",
191 | "%cd /content/MusicTransformer-Pytorch/dataset/\n",
192 | "!wget 'https://storage.googleapis.com/magentadata/datasets/maestro/v2.0.0/maestro-v2.0.0-midi.zip'\n",
193 | "!unzip maestro-v2.0.0-midi.zip\n",
194 | "%cd /content/MusicTransformer-Pytorch/"
195 | ],
196 | "execution_count": null,
197 | "outputs": []
198 | },
199 | {
200 | "cell_type": "code",
201 | "metadata": {
202 | "id": "yXiyUuuonMqM",
203 | "colab_type": "code",
204 | "cellView": "form",
205 | "colab": {}
206 | },
207 | "source": [
208 | "#@title Prepare directory sctructure and MIDI processor\n",
209 | "%cd /content/\n",
210 | "!mv midi-neural-processor midi_processor\n",
211 | "%cd /content/MusicTransformer-Pytorch/"
212 | ],
213 | "execution_count": null,
214 | "outputs": []
215 | },
216 | {
217 | "cell_type": "code",
218 | "metadata": {
219 | "id": "vN-bpkEGxSMY",
220 | "colab_type": "code",
221 | "cellView": "form",
222 | "colab": {}
223 | },
224 | "source": [
225 | "#@title Process MAESTRO MIDI DataSet\n",
226 | "!python3 preprocess_midi.py '/content/MusicTransformer-Pytorch/dataset/maestro-v2.0.0'"
227 | ],
228 | "execution_count": null,
229 | "outputs": []
230 | },
231 | {
232 | "cell_type": "markdown",
233 | "metadata": {
234 | "id": "XKz4SKoeXYWc",
235 | "colab_type": "text"
236 | },
237 | "source": [
238 | "#Option 2: Your own Custom MIDI DataSet"
239 | ]
240 | },
241 | {
242 | "cell_type": "code",
243 | "metadata": {
244 | "id": "27zmkAM9vEGX",
245 | "colab_type": "code",
246 | "cellView": "form",
247 | "colab": {}
248 | },
249 | "source": [
250 | "#@title Create directory structure for the DataSet and prep MIDI processor\n",
251 | "\n",
252 | "!mkdir '/content/MusicTransformer-Pytorch/dataset/e_piano/'\n",
253 | "!mkdir '/content/MusicTransformer-Pytorch/dataset/e_piano/train'\n",
254 | "!mkdir '/content/MusicTransformer-Pytorch/dataset/e_piano/test'\n",
255 | "!mkdir '/content/MusicTransformer-Pytorch/dataset/e_piano/val'\n",
256 | "!mkdir '/content/MusicTransformer-Pytorch/dataset/e_piano/custom_midis'\n",
257 | "\n",
258 | "%cd /content/\n",
259 | "!mv midi-neural-processor midi_processor\n",
260 | "%cd /content/MusicTransformer-Pytorch/"
261 | ],
262 | "execution_count": null,
263 | "outputs": []
264 | },
265 | {
266 | "cell_type": "code",
267 | "metadata": {
268 | "id": "KUXaozztvGU2",
269 | "colab_type": "code",
270 | "cellView": "form",
271 | "colab": {}
272 | },
273 | "source": [
274 | "#@title Upload your custom MIDI DataSet to created \"dataset/e_piano/custom_midis\" folder through this cell or manually through any other means. You can also use ready-to-use DataSets below\n",
275 | "from google.colab import files\n",
276 | "%cd '/content/MusicTransformer-Pytorch/dataset/e_piano/custom_midis'\n",
277 | "uploaded = files.upload()\n",
278 | "\n",
279 | "for fn in uploaded.keys():\n",
280 | " print('User uploaded file \"{name}\" with length {length} bytes'.format(\n",
281 | " name=fn, length=len(uploaded[fn])))"
282 | ],
283 | "execution_count": null,
284 | "outputs": []
285 | },
286 | {
287 | "cell_type": "code",
288 | "metadata": {
289 | "id": "uDsmK-vkwOgl",
290 | "colab_type": "code",
291 | "cellView": "form",
292 | "colab": {}
293 | },
294 | "source": [
295 | "#@title (The Best Choice/Works best stand-alone) Super Piano 2 Original 2500 MIDIs of Piano Music\n",
296 | "%cd /content/MusicTransformer-Pytorch/dataset/e_piano/custom_midis\n",
297 | "!wget 'https://github.com/asigalov61/SuperPiano/raw/master/Super_Piano_2_MIDI_DataSet_CC_BY_NC_SA.zip'\n",
298 | "!unzip -j 'Super_Piano_2_MIDI_DataSet_CC_BY_NC_SA.zip'\n",
299 | "!rm Super_Piano_2_MIDI_DataSet_CC_BY_NC_SA.zip"
300 | ],
301 | "execution_count": null,
302 | "outputs": []
303 | },
304 | {
305 | "cell_type": "code",
306 | "metadata": {
307 | "id": "feA03YKvwgaV",
308 | "colab_type": "code",
309 | "cellView": "form",
310 | "colab": {}
311 | },
312 | "source": [
313 | "#@title (Second Best Choice/Works best stand-alone) Alex Piano Only Original 450 MIDIs \n",
314 | "%cd /content/MusicTransformer-Pytorch/dataset/e_piano/custom_midis\n",
315 | "!wget 'https://github.com/asigalov61/AlexMIDIDataSet/raw/master/AlexMIDIDataSet-CC-BY-NC-SA-Piano-Only.zip'\n",
316 | "!unzip -j 'AlexMIDIDataSet-CC-BY-NC-SA-Piano-Only.zip'\n",
317 | "!rm AlexMIDIDataSet-CC-BY-NC-SA-All-Drafts-Piano-Only.zip"
318 | ],
319 | "execution_count": null,
320 | "outputs": []
321 | },
322 | {
323 | "cell_type": "markdown",
324 | "metadata": {
325 | "id": "e-jAV_Qv5Fn_",
326 | "colab_type": "text"
327 | },
328 | "source": [
329 | "For now, we are going to split the dataset by random into \"test\"/\"val\" dirs which is not ideal. So feel free to modify the code to your liking to achieve better training results with this implementation."
330 | ]
331 | },
332 | {
333 | "cell_type": "code",
334 | "metadata": {
335 | "id": "IZ5c6d5lXemo",
336 | "colab_type": "code",
337 | "cellView": "form",
338 | "colab": {}
339 | },
340 | "source": [
341 | "#@title Process your custom MIDI DataSet :)\n",
342 | "%cd /content/MusicTransformer-Pytorch\n",
343 | "from processor import encode_midi\n",
344 | "\n",
345 | "import os\n",
346 | "import random\n",
347 | "\n",
348 | "\n",
349 | "\n",
350 | "%cd '/content/MusicTransformer-Pytorch/dataset/e_piano/custom_midis'\n",
351 | "\n",
352 | "custom_MIDI_DataSet_dir = '/content/MusicTransformer-Pytorch/dataset/e_piano/custom_midis'\n",
353 | "\n",
354 | "train_dir = '/content/MusicTransformer-Pytorch/dataset/e_piano/train' # split_type = 0\n",
355 | "test_dir = '/content/MusicTransformer-Pytorch/dataset/e_piano/test' # split_type = 1 \n",
356 | "val_dir = '/content/MusicTransformer-Pytorch/dataset/e_piano/val' # split_type = 2\n",
357 | "\n",
358 | "total_count = 0\n",
359 | "train_count = 0\n",
360 | "val_count = 0\n",
361 | "test_count = 0\n",
362 | "\n",
363 | "f_ext = '.pickle'\n",
364 | "fileList = os.listdir(custom_MIDI_DataSet_dir)\n",
365 | "for file in fileList:\n",
366 | " # we gonna split by a random selection for now\n",
367 | " \n",
368 | " split = random.randint(1, 2)\n",
369 | " if (split == 0):\n",
370 | " o_file = os.path.join(train_dir, file+f_ext)\n",
371 | " train_count += 1\n",
372 | "\n",
373 | " elif (split == 2):\n",
374 | " o_file0 = os.path.join(train_dir, file+f_ext)\n",
375 | " train_count += 1\n",
376 | " o_file = os.path.join(val_dir, file+f_ext)\n",
377 | " val_count += 1\n",
378 | "\n",
379 | " elif (split == 1):\n",
380 | " o_file0 = os.path.join(train_dir, file+f_ext)\n",
381 | " train_count += 1\n",
382 | " o_file = os.path.join(test_dir, file+f_ext)\n",
383 | " test_count += 1\n",
384 | " try:\n",
385 | " prepped = encode_midi(file)\n",
386 | " o_stream = open(o_file0, \"wb\")\n",
387 | " pickle.dump(prepped, o_stream)\n",
388 | " o_stream.close()\n",
389 | "\n",
390 | " prepped = encode_midi(file)\n",
391 | " o_stream = open(o_file, \"wb\")\n",
392 | " pickle.dump(prepped, o_stream)\n",
393 | " o_stream.close()\n",
394 | " \n",
395 | " print(file)\n",
396 | " print(o_file)\n",
397 | " print('Coverted!') \n",
398 | " except KeyboardInterrupt: \n",
399 | " raise \n",
400 | " except:\n",
401 | " print('Bad file. Skipping...')\n",
402 | "\n",
403 | "print('Done')\n",
404 | "print(\"Num Train:\", train_count)\n",
405 | "print(\"Num Val:\", val_count)\n",
406 | "print(\"Num Test:\", test_count)\n",
407 | "print(\"Total Count:\", train_count)\n",
408 | "\n",
409 | "%cd /content/MusicTransformer-Pytorch"
410 | ],
411 | "execution_count": null,
412 | "outputs": []
413 | },
414 | {
415 | "cell_type": "markdown",
416 | "metadata": {
417 | "id": "JwCQIziNwHxe",
418 | "colab_type": "text"
419 | },
420 | "source": [
421 | "#Train the Model"
422 | ]
423 | },
424 | {
425 | "cell_type": "code",
426 | "metadata": {
427 | "id": "hwisXl2Iy_Xf",
428 | "colab_type": "code",
429 | "cellView": "form",
430 | "colab": {}
431 | },
432 | "source": [
433 | "#@title Activate Tensorboard Graphs/Stats to monitor/evaluate model perfomance during and after training runs\n",
434 | "# Load the TensorBoard notebook extension\n",
435 | "%reload_ext tensorboard\n",
436 | "import tensorflow as tf\n",
437 | "import datetime, os\n",
438 | "%tensorboard --logdir /content/MusicTransformer-Pytorch/rpr"
439 | ],
440 | "execution_count": null,
441 | "outputs": []
442 | },
443 | {
444 | "cell_type": "code",
445 | "metadata": {
446 | "id": "Sbv_sJyLq5om",
447 | "colab_type": "code",
448 | "cellView": "form",
449 | "colab": {}
450 | },
451 | "source": [
452 | "#@title Start to Train the Model\n",
453 | "batch_size = 4 #@param {type:\"slider\", min:0, max:8, step:1}\n",
454 | "number_of_training_epochs = 150 #@param {type:\"slider\", min:0, max:200, step:1}\n",
455 | "maximum_output_MIDI_sequence = 2048 #@param {type:\"slider\", min:0, max:8192, step:128}\n",
456 | "!python3 train.py -output_dir rpr --rpr -batch_size=$batch_size -epochs=$number_of_training_epochs -max_sequence=$maximum_output_MIDI_sequence #-n_layers -num_heads -d_model -dim_feedforward"
457 | ],
458 | "execution_count": null,
459 | "outputs": []
460 | },
461 | {
462 | "cell_type": "code",
463 | "metadata": {
464 | "id": "9VLdhokSGUAu",
465 | "colab_type": "code",
466 | "colab": {},
467 | "cellView": "form"
468 | },
469 | "source": [
470 | "#@title Re-Start Training from a certain checkpoint and epoch\n",
471 | "batch_size = 4 #@param {type:\"slider\", min:0, max:8, step:1}\n",
472 | "number_of_training_epochs = 150 #@param {type:\"slider\", min:0, max:200, step:1}\n",
473 | "maximum_output_MIDI_sequence = 2048 #@param {type:\"slider\", min:0, max:8192, step:128}\n",
474 | "saved_checkpoint_full_path = \"/content/MusicTransformer-Pytorch/rpr/weights/epoch_0033.pickle\" #@param {type:\"string\"}\n",
475 | "continue_epoch_number = 33 #@param {type:\"integer\"}\n",
476 | "\n",
477 | "!python3 train.py -output_dir rpr --rpr -batch_size=$batch_size -epochs=$number_of_training_epochs -max_sequence=$maximum_output_MIDI_sequence -continue_weights $saved_checkpoint_full_path -continue_epoch $continue_epoch_number #-n_layers -num_heads -d_model -dim_feedforward"
478 | ],
479 | "execution_count": null,
480 | "outputs": []
481 | },
482 | {
483 | "cell_type": "markdown",
484 | "metadata": {
485 | "id": "k1D-o-E-TnI8",
486 | "colab_type": "text"
487 | },
488 | "source": [
489 | "###Evaluate the resulted models"
490 | ]
491 | },
492 | {
493 | "cell_type": "code",
494 | "metadata": {
495 | "id": "qQLOmv7wrOos",
496 | "colab_type": "code",
497 | "cellView": "form",
498 | "colab": {}
499 | },
500 | "source": [
501 | "#@title Evaluate Best Resulting Accuracy Model (best_acc_weights.pickle)\n",
502 | "!python3 evaluate.py -model_weights rpr/results/best_acc_weights.pickle --rpr"
503 | ],
504 | "execution_count": null,
505 | "outputs": []
506 | },
507 | {
508 | "cell_type": "code",
509 | "metadata": {
510 | "id": "c7QftGOfTyx2",
511 | "colab_type": "code",
512 | "cellView": "form",
513 | "colab": {}
514 | },
515 | "source": [
516 | "#@title Evaluate Best Resulting Loss Model (best_loss_weights.pickle)\n",
517 | "!python3 evaluate.py -model_weights rpr/results/best_loss_weights.pickle --rpr"
518 | ],
519 | "execution_count": null,
520 | "outputs": []
521 | },
522 | {
523 | "cell_type": "code",
524 | "metadata": {
525 | "id": "MusrrrOxt1uy",
526 | "colab_type": "code",
527 | "cellView": "form",
528 | "colab": {}
529 | },
530 | "source": [
531 | "#@title Graph the results\n",
532 | "import argparse\n",
533 | "import os\n",
534 | "import csv\n",
535 | "import math\n",
536 | "import matplotlib.pyplot as plt\n",
537 | "\n",
538 | "RESULTS_FILE = \"results.csv\"\n",
539 | "EPOCH_IDX = 0\n",
540 | "LR_IDX = 1\n",
541 | "EVAL_LOSS_IDX = 4\n",
542 | "EVAL_ACC_IDX = 5\n",
543 | "\n",
544 | "SPLITTER = '?'\n",
545 | "\n",
546 | "\n",
547 | "def graph_results(input_dirs=\"/content/MusicTransformer-Pytorch/rpr/results\", output_dir=None, model_names=None, epoch_start=0, epoch_end=None):\n",
548 | " \"\"\"\n",
549 | " ----------\n",
550 | " Author: Damon Gwinn\n",
551 | " ----------\n",
552 | " Graphs model training and evaluation data\n",
553 | " ----------\n",
554 | " \"\"\"\n",
555 | "\n",
556 | " input_dirs = input_dirs.split(SPLITTER)\n",
557 | "\n",
558 | " if(model_names is not None):\n",
559 | " model_names = model_names.split(SPLITTER)\n",
560 | " if(len(model_names) != len(input_dirs)):\n",
561 | " print(\"Error: len(model_names) != len(input_dirs)\")\n",
562 | " return\n",
563 | "\n",
564 | " #Initialize Loss and Accuracy arrays\n",
565 | " loss_arrs = []\n",
566 | " accuracy_arrs = []\n",
567 | " epoch_counts = []\n",
568 | " lrs = []\n",
569 | "\n",
570 | " for input_dir in input_dirs:\n",
571 | " loss_arr = []\n",
572 | " accuracy_arr = []\n",
573 | " epoch_count = []\n",
574 | " lr_arr = []\n",
575 | "\n",
576 | " f = os.path.join(input_dir, RESULTS_FILE)\n",
577 | " with open(f, \"r\") as i_stream:\n",
578 | " reader = csv.reader(i_stream)\n",
579 | " next(reader)\n",
580 | "\n",
581 | " lines = [line for line in reader]\n",
582 | "\n",
583 | " if(epoch_end is None):\n",
584 | " epoch_end = math.inf\n",
585 | "\n",
586 | " epoch_start = max(epoch_start, 0)\n",
587 | " epoch_start = min(epoch_start, epoch_end)\n",
588 | "\n",
589 | " for line in lines:\n",
590 | " epoch = line[EPOCH_IDX]\n",
591 | " lr = line[LR_IDX]\n",
592 | " accuracy = line[EVAL_ACC_IDX]\n",
593 | " loss = line[EVAL_LOSS_IDX]\n",
594 | "\n",
595 | " if(int(epoch) >= epoch_start and int(epoch) < epoch_end):\n",
596 | " accuracy_arr.append(float(accuracy))\n",
597 | " loss_arr.append(float(loss))\n",
598 | " epoch_count.append(int(epoch))\n",
599 | " lr_arr.append(float(lr))\n",
600 | "\n",
601 | " loss_arrs.append(loss_arr)\n",
602 | " accuracy_arrs.append(accuracy_arr)\n",
603 | " epoch_counts.append(epoch_count)\n",
604 | " lrs.append(lr_arr)\n",
605 | "\n",
606 | " if(output_dir is not None):\n",
607 | " try:\n",
608 | " os.mkdir(output_dir)\n",
609 | " except OSError:\n",
610 | " print (\"Creation of the directory %s failed\" % output_dir)\n",
611 | " else:\n",
612 | " print (\"Successfully created the directory %s\" % output_dir)\n",
613 | "\n",
614 | " ##### LOSS #####\n",
615 | " for i in range(len(loss_arrs)):\n",
616 | " if(model_names is None):\n",
617 | " name = None\n",
618 | " else:\n",
619 | " name = model_names[i]\n",
620 | "\n",
621 | " #Create and save plots to output folder\n",
622 | " plt.plot(epoch_counts[i], loss_arrs[i], label=name)\n",
623 | " plt.title(\"Loss Results\")\n",
624 | " plt.ylabel('Loss (Cross Entropy)')\n",
625 | " plt.xlabel('Epochs')\n",
626 | " fig1 = plt.gcf()\n",
627 | "\n",
628 | " plt.legend(loc=\"upper left\")\n",
629 | "\n",
630 | " if(output_dir is not None):\n",
631 | " fig1.savefig(os.path.join(output_dir, 'loss_graph.png'))\n",
632 | "\n",
633 | " plt.show()\n",
634 | "\n",
635 | " ##### ACCURACY #####\n",
636 | " for i in range(len(accuracy_arrs)):\n",
637 | " if(model_names is None):\n",
638 | " name = None\n",
639 | " else:\n",
640 | " name = model_names[i]\n",
641 | "\n",
642 | " #Create and save plots to output folder\n",
643 | " plt.plot(epoch_counts[i], accuracy_arrs[i], label=name)\n",
644 | " plt.title(\"Accuracy Results\")\n",
645 | " plt.ylabel('Accuracy')\n",
646 | " plt.xlabel('Epochs')\n",
647 | " fig2 = plt.gcf()\n",
648 | "\n",
649 | " plt.legend(loc=\"upper left\")\n",
650 | "\n",
651 | " if(output_dir is not None):\n",
652 | " fig2.savefig(os.path.join(output_dir, 'accuracy_graph.png'))\n",
653 | "\n",
654 | " plt.show()\n",
655 | "\n",
656 | " ##### LR #####\n",
657 | " for i in range(len(lrs)):\n",
658 | " if(model_names is None):\n",
659 | " name = None\n",
660 | " else:\n",
661 | " name = model_names[i]\n",
662 | "\n",
663 | " #Create and save plots to output folder\n",
664 | " plt.plot(epoch_counts[i], lrs[i], label=name)\n",
665 | " plt.title(\"Learn Rate Results\")\n",
666 | " plt.ylabel('Learn Rate')\n",
667 | " plt.xlabel('Epochs')\n",
668 | " fig2 = plt.gcf()\n",
669 | "\n",
670 | " plt.legend(loc=\"upper left\")\n",
671 | "\n",
672 | " if(output_dir is not None):\n",
673 | " fig2.savefig(os.path.join(output_dir, 'lr_graph.png'))\n",
674 | "\n",
675 | " plt.show()\n",
676 | "graph_results('/content/MusicTransformer-Pytorch/rpr/results', model_names='rpr')"
677 | ],
678 | "execution_count": null,
679 | "outputs": []
680 | },
681 | {
682 | "cell_type": "markdown",
683 | "metadata": {
684 | "id": "fxHrTsFUdn-r",
685 | "colab_type": "text"
686 | },
687 | "source": [
688 | "To have the model continue your custom MIDI enter the following into the custom_MIDI field below:\n",
689 | "\n",
690 | "-primer_file '/content/some_dir/some_seed_midi.mid'\n",
691 | "\n",
692 | "For example: -primer_file '/content/MusicTransformer-Pytorch/seed.mid'"
693 | ]
694 | },
695 | {
696 | "cell_type": "markdown",
697 | "metadata": {
698 | "id": "EJXWoBMWL3ph",
699 | "colab_type": "text"
700 | },
701 | "source": [
702 | "# Generate and Explore the output :)"
703 | ]
704 | },
705 | {
706 | "cell_type": "code",
707 | "metadata": {
708 | "id": "czNulONr4tB6",
709 | "colab_type": "code",
710 | "cellView": "form",
711 | "colab": {}
712 | },
713 | "source": [
714 | "#@title Generate, Plot, Graph, Save, Download, and Render the resulting output\n",
715 | "number_of_tokens_to_generate = 1023 #@param {type:\"slider\", min:1, max:2048, step:1}\n",
716 | "priming_sequence_length = 65 #@param {type:\"slider\", min:1, max:2048, step:8}\n",
717 | "maximum_possible_output_sequence = 2048 #@param {type:\"slider\", min:0, max:2048, step:8}\n",
718 | "select_model = \"/content/MusicTransformer-Pytorch/rpr/results/best_loss_weights.pickle\" #@param [\"/content/MusicTransformer-Pytorch/rpr/results/best_acc_weights.pickle\", \"/content/MusicTransformer-Pytorch/rpr/results/best_loss_weights.pickle\"]\n",
719 | "custom_MIDI = \"\" #@param {type:\"string\"}\n",
720 | "\n",
721 | "import processor\n",
722 | "from processor import encode_midi, decode_midi\n",
723 | "\n",
724 | "!python generate.py -output_dir output -model_weights=$select_model --rpr -target_seq_length=$number_of_tokens_to_generate -num_prime=$priming_sequence_length -max_sequence=$maximum_possible_output_sequence $custom_MIDI #\n",
725 | "\n",
726 | "print('Successfully exported the output to output folder. To primer.mid and rand.mid')\n",
727 | "\n",
728 | "# set the src and play\n",
729 | "FluidSynth(\"/content/font.sf2\").midi_to_audio('/content/MusicTransformer-Pytorch/output/rand.mid', '/content/MusicTransformer-Pytorch/output/output.wav')\n",
730 | "\n",
731 | "from google.colab import files\n",
732 | "files.download('/content/MusicTransformer-Pytorch/output/rand.mid')\n",
733 | "files.download('/content/MusicTransformer-Pytorch/output/primer.mid')\n",
734 | "\n",
735 | "Audio('/content/MusicTransformer-Pytorch/output/output.wav')\n"
736 | ],
737 | "execution_count": null,
738 | "outputs": []
739 | },
740 | {
741 | "cell_type": "code",
742 | "metadata": {
743 | "id": "IG48uyKGzcTI",
744 | "colab_type": "code",
745 | "cellView": "form",
746 | "colab": {}
747 | },
748 | "source": [
749 | "#@title Plot and Graph the Output :)\n",
750 | "graphs_length_inches = 18 #@param {type:\"slider\", min:0, max:20, step:1}\n",
751 | "notes_graph_height = 6 #@param {type:\"slider\", min:0, max:20, step:1}\n",
752 | "highest_displayed_pitch = 92 #@param {type:\"slider\", min:1, max:128, step:1}\n",
753 | "lowest_displayed_pitch = 24 #@param {type:\"slider\", min:1, max:128, step:1}\n",
754 | "piano_roll_color_map = \"Blues\"\n",
755 | "\n",
756 | "import librosa\n",
757 | "import numpy as np\n",
758 | "import pretty_midi\n",
759 | "import pypianoroll\n",
760 | "from pypianoroll import Multitrack, Track\n",
761 | "import matplotlib\n",
762 | "import matplotlib.pyplot as plt\n",
763 | "#matplotlib.use('SVG')\n",
764 | "# For plotting\n",
765 | "import mir_eval.display\n",
766 | "import librosa.display\n",
767 | "%matplotlib inline\n",
768 | "\n",
769 | "\n",
770 | "midi_data = pretty_midi.PrettyMIDI('/content/MusicTransformer-Pytorch/output/rand.mid')\n",
771 | "\n",
772 | "def plot_piano_roll(pm, start_pitch, end_pitch, fs=100):\n",
773 | " # Use librosa's specshow function for displaying the piano roll\n",
774 | " librosa.display.specshow(pm.get_piano_roll(fs)[start_pitch:end_pitch],\n",
775 | " hop_length=1, sr=fs, x_axis='time', y_axis='cqt_note',\n",
776 | " fmin=pretty_midi.note_number_to_hz(start_pitch))\n",
777 | "\n",
778 | "\n",
779 | "\n",
780 | "roll = np.zeros([int(graphs_length_inches), 128])\n",
781 | "# Plot the output\n",
782 | "\n",
783 | "track = Multitrack('/content/MusicTransformer-Pytorch/output/rand.mid', name='track')\n",
784 | "plt.figure(figsize=[graphs_length_inches, notes_graph_height])\n",
785 | "fig, ax = track.plot()\n",
786 | "fig.set_size_inches(graphs_length_inches, notes_graph_height)\n",
787 | "plt.figure(figsize=[graphs_length_inches, notes_graph_height])\n",
788 | "ax2 = plot_piano_roll(midi_data, int(lowest_displayed_pitch), int(highest_displayed_pitch))\n",
789 | "plt.show(block=False)"
790 | ],
791 | "execution_count": null,
792 | "outputs": []
793 | },
794 | {
795 | "cell_type": "markdown",
796 | "metadata": {
797 | "id": "VFMWSDq7ZKM2",
798 | "colab_type": "text"
799 | },
800 | "source": [
801 | "### Save to Google Drive (Standard GD connect code)"
802 | ]
803 | },
804 | {
805 | "cell_type": "code",
806 | "metadata": {
807 | "id": "n-A3ju-Fz0Eh",
808 | "colab_type": "code",
809 | "colab": {}
810 | },
811 | "source": [
812 | "from google.colab import drive\n",
813 | "drive.mount('/content/drive')"
814 | ],
815 | "execution_count": null,
816 | "outputs": []
817 | }
818 | ]
819 | }
--------------------------------------------------------------------------------
/Super_Piano_3_Alt_2.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "Super Piano 3 Alt 2.ipynb",
7 | "provenance": [],
8 | "private_outputs": true,
9 | "collapsed_sections": [],
10 | "machine_shape": "hm",
11 | "authorship_tag": "ABX9TyML/l9/cIXdhZnYU8JuN0LM",
12 | "include_colab_link": true
13 | },
14 | "kernelspec": {
15 | "name": "python3",
16 | "display_name": "Python 3"
17 | },
18 | "accelerator": "GPU"
19 | },
20 | "cells": [
21 | {
22 | "cell_type": "markdown",
23 | "metadata": {
24 | "id": "view-in-github",
25 | "colab_type": "text"
26 | },
27 | "source": [
28 | "
"
29 | ]
30 | },
31 | {
32 | "cell_type": "markdown",
33 | "metadata": {
34 | "id": "Cj9PFo6cF670"
35 | },
36 | "source": [
37 | "# Super Piano 3\n",
38 | "## Google Music Transformer\n",
39 | "\n",
40 | "### All thanks and credit for this colab go out to Prayag Chatha on whose repo and code it is based: https://github.com/chathasphere/pno-ai"
41 | ]
42 | },
43 | {
44 | "cell_type": "code",
45 | "metadata": {
46 | "id": "F-PCBbGB11Dp",
47 | "cellView": "form"
48 | },
49 | "source": [
50 | "#@title Clone pno-ai repo and install dependencies\n",
51 | "!git clone 'https://github.com/asigalov61/pno-ai'\n",
52 | "!pip install pretty_midi\n",
53 | "!pip install rtmidi"
54 | ],
55 | "execution_count": null,
56 | "outputs": []
57 | },
58 | {
59 | "cell_type": "code",
60 | "metadata": {
61 | "id": "VsR2kUVY6SWs",
62 | "cellView": "form"
63 | },
64 | "source": [
65 | "#@title Import modules and setup main (hyper)parameters\n",
66 | "%cd /content/pno-ai/\n",
67 | "import os, time, datetime\n",
68 | "import torch\n",
69 | "import torch.nn as nn\n",
70 | "torch.set_default_tensor_type(torch.cuda.FloatTensor)\n",
71 | "from random import shuffle\n",
72 | "from preprocess import PreprocessingPipeline\n",
73 | "from train import train\n",
74 | "from model import MusicTransformer\n",
75 | "\n",
76 | "n_epochs = 60\n",
77 | "batch_size = 128\n",
78 | "sampling_rate = 125\n",
79 | "n_velocity_bins = 32\n",
80 | "seq_length = 256\n",
81 | "n_tokens = 256 + sampling_rate + n_velocity_bins\n",
82 | "transformer = MusicTransformer(n_tokens, seq_length, \n",
83 | " d_model = 128, n_heads = 8, d_feedforward=512, \n",
84 | " depth = 6, positional_encoding=True, relative_pos=True)"
85 | ],
86 | "execution_count": null,
87 | "outputs": []
88 | },
89 | {
90 | "cell_type": "code",
91 | "metadata": {
92 | "id": "ht3vjmhM2TgU",
93 | "cellView": "form"
94 | },
95 | "source": [
96 | "#@title Download Google Magenta MAESTRO v.2.0.0 Piano MIDI Dataset (~1300 MIDIs)\n",
97 | "%cd /content/pno-ai/data\n",
98 | "!wget 'https://storage.googleapis.com/magentadata/datasets/maestro/v2.0.0/maestro-v2.0.0-midi.zip'\n",
99 | "!unzip -j maestro-v2.0.0-midi.zip\n",
100 | "!rm maestro-v2.0.0-midi.zip\n",
101 | "%cd /content/pno-ai"
102 | ],
103 | "execution_count": null,
104 | "outputs": []
105 | },
106 | {
107 | "cell_type": "code",
108 | "metadata": {
109 | "id": "JfQ3wCXBEKW1"
110 | },
111 | "source": [
112 | "%cd /content/pno-ai/data\n",
113 | "!unzip -j '/content/pno-ai/data/Super-Piano-2-Performance-DataSet-CC-BY-NC-SA.zip'\n",
114 | "!rm '/content/pno-ai/data/Super-Piano-2-Performance-DataSet-CC-BY-NC-SA.zip'"
115 | ],
116 | "execution_count": null,
117 | "outputs": []
118 | },
119 | {
120 | "cell_type": "code",
121 | "metadata": {
122 | "id": "WZpRFWmSC4cD",
123 | "cellView": "form"
124 | },
125 | "source": [
126 | "#@title Process custom MIDI dataset\n",
127 | "%cd /content/pno-ai\n",
128 | "pipeline = PreprocessingPipeline(input_dir=\"data\", stretch_factors=[0.975, 1, 1.025],\n",
129 | " split_size=30, sampling_rate=sampling_rate, n_velocity_bins=n_velocity_bins,\n",
130 | " transpositions=range(-2,3), training_val_split=0.9, max_encoded_length=seq_length+1,\n",
131 | " min_encoded_length=257)\n",
132 | "\n",
133 | "pipeline_start = time.time()\n",
134 | "pipeline.run()\n",
135 | "runtime = time.time() - pipeline_start\n",
136 | "print(f\"MIDI pipeline runtime: {runtime / 60 : .1f}m\")"
137 | ],
138 | "execution_count": null,
139 | "outputs": []
140 | },
141 | {
142 | "cell_type": "code",
143 | "metadata": {
144 | "id": "4gKYrVKRCpM1",
145 | "cellView": "form"
146 | },
147 | "source": [
148 | "#@title Train the model\n",
149 | "%cd '/content/pno-ai'\n",
150 | "today = datetime.date.today().strftime('%m%d%Y')\n",
151 | "checkpoint = f\"saved_models/tf_{today}\"\n",
152 | "\n",
153 | "training_sequences = pipeline.encoded_sequences['training']\n",
154 | "validation_sequences = pipeline.encoded_sequences['validation']\n",
155 | "\n",
156 | "\n",
157 | "train(transformer, training_sequences, validation_sequences,\n",
158 | " epochs = n_epochs, evaluate_per = 1, custom_schedule=True, custom_loss=True,\n",
159 | " batch_size = batch_size, batches_per_print=100,\n",
160 | " padding_index=0, checkpoint_path=checkpoint)"
161 | ],
162 | "execution_count": null,
163 | "outputs": []
164 | },
165 | {
166 | "cell_type": "code",
167 | "metadata": {
168 | "id": "S8tuYH63MRXp",
169 | "cellView": "form"
170 | },
171 | "source": [
172 | "#@title Save the model\n",
173 | "%cd /content/pno-ai\n",
174 | "torch.save(transformer, 'trained_model.pth')"
175 | ],
176 | "execution_count": null,
177 | "outputs": []
178 | },
179 | {
180 | "cell_type": "code",
181 | "metadata": {
182 | "id": "t1MTzF3NDKYb",
183 | "cellView": "form"
184 | },
185 | "source": [
186 | "#@title Load pre-trained checkpoint if needed\n",
187 | "%cd /content/pno-ai\n",
188 | "transformer.load_state_dict(torch.load('/content/pno-ai/saved_models/tf_09232020_e4'))\n",
189 | "print(\"Successfully loaded checkpoint!\")\n",
190 | "transformer.eval()"
191 | ],
192 | "execution_count": null,
193 | "outputs": []
194 | },
195 | {
196 | "cell_type": "code",
197 | "metadata": {
198 | "id": "7qq3cS3Gmj2G",
199 | "cellView": "form"
200 | },
201 | "source": [
202 | "#@title Define Helper Functions\n",
203 | "import numpy as np\n",
204 | "from pretty_midi import Note, PrettyMIDI, Instrument\n",
205 | "import torch.nn.functional as F\n",
206 | "import copy, pathlib\n",
207 | "\n",
208 | "def vectorize(sequence):\n",
209 | " \"\"\"\n",
210 | " Converts a list of pretty_midi Note objects into a numpy array of\n",
211 | " dimension (n_notes x 4)\n",
212 | " \"\"\"\n",
213 | " array = [[note.start, note.end, note.pitch, note.velocity] for\n",
214 | " note in sequence]\n",
215 | " return np.asarray(array)\n",
216 | "\n",
217 | "def devectorize(note_array):\n",
218 | " \"\"\"\n",
219 | " Converts a vectorized note sequence into a list of pretty_midi Note\n",
220 | " objects\n",
221 | " \"\"\"\n",
222 | " return [Note(start = a[0], end = a[1], pitch=a[2],\n",
223 | " velocity=a[3]) for a in note_array.tolist()]\n",
224 | "\n",
225 | "\n",
226 | "def one_hot(sequence, n_states):\n",
227 | " \"\"\"\n",
228 | " Given a list of integers and the maximal number of unique values found\n",
229 | " in the list, return a one-hot encoded tensor of shape (m, n)\n",
230 | " where m is sequence length and n is n_states.\n",
231 | " \"\"\"\n",
232 | " if torch.cuda.is_available():\n",
233 | " return torch.eye(n_states)[sequence,:].cuda()\n",
234 | " else:\n",
235 | " return torch.eye(n_states)[sequence,:]\n",
236 | "\n",
237 | "def decode_one_hot(vector):\n",
238 | " '''\n",
239 | " Given a one-hot encoded vector, return the non-zero index\n",
240 | " '''\n",
241 | " return vector.nonzero().item()\n",
242 | "\n",
243 | "def prepare_batches(sequences, batch_size):\n",
244 | " \"\"\"\n",
245 | " Splits a list of sequences into batches of a fixed size. Each sequence yields an input sequence\n",
246 | " and a target sequence, with the latter one time step ahead. For example, the sequence \"to be or not\n",
247 | " to be\" gives an input sequence of \"to be or not to b\" and a target sequence of \"o be or not to be.\"\n",
248 | " \"\"\"\n",
249 | " n_sequences = len(sequences)\n",
250 | " for i in range(0, n_sequences, batch_size):\n",
251 | " batch = sequences[i:i+batch_size]\n",
252 | "\t#needs to be in sorted order for packing batches to work\n",
253 | " batch = sorted(batch, key = len, reverse=True)\n",
254 | " input_sequences, target_sequences = [], []\n",
255 | "\n",
256 | " for sequence in batch:\n",
257 | " input_sequences.append(sequence[:-1])\n",
258 | " target_sequences.append(sequence[1:])\n",
259 | "\n",
260 | " yield input_sequences, target_sequences\n",
261 | "\n",
262 | "def clones(module, N):\n",
263 | " \"Clone N identical layers of a module\"\n",
264 | " return torch.nn.ModuleList([copy.deepcopy(module) for i in range(N)])\n",
265 | "\n",
266 | "def d(tensor=None):\n",
267 | " if tensor is None:\n",
268 | " return 'cuda' if torch.cuda.is_available() else 'cpu'\n",
269 | " return 'cuda' if tensor.is_cuda else 'cpu'\n",
270 | "\n",
271 | "def write_midi(note_sequence, output_dir, filename):\n",
272 | "\n",
273 | " #make output directory\n",
274 | " pathlib.Path(output_dir).mkdir(parents=True, exist_ok=True)\n",
275 | "\n",
276 | " #generate midi\n",
277 | " midi = PrettyMIDI()\n",
278 | " piano_track = Instrument(program=0, is_drum=False, name=filename)\n",
279 | " piano_track.notes = note_sequence\n",
280 | " midi.instruments.append(piano_track)\n",
281 | " output_name = output_dir + f\"{filename}.midi\"\n",
282 | " midi.write(output_name)\n",
283 | "\n",
284 | "def sample(model, sample_length, prime_sequence=[], temperature=1):\n",
285 | " \"\"\"\n",
286 | " Generate a MIDI event sequence of a fixed length by randomly sampling from a model's distribution of sequences. Optionally, \"seed\" the sequence with a prime. A well-trained model will create music that responds to the prime and develops upon it.\n",
287 | " \"\"\"\n",
288 | " #deactivate training mode\n",
289 | " model.eval()\n",
290 | " if len(prime_sequence) == 0:\n",
291 | " #if no prime is provided, randomly select a starting event\n",
292 | " input_sequence = [np.random.randint(model.n_tokens)]\n",
293 | " else:\n",
294 | " input_sequence = prime_sequence.copy()\n",
295 | "\n",
296 | " #add singleton dimension for the batch\n",
297 | " input_tensor = torch.LongTensor(input_sequence).unsqueeze(0).cuda()\n",
298 | "\n",
299 | " for i in range(sample_length):\n",
300 | " #select probabilities of *next* token\n",
301 | " out = model(input_tensor)[0, -1, :]\n",
302 | " #out is a 1d tensor of shape (n_tokens)\n",
303 | " probs = F.softmax(out / temperature, dim=0)\n",
304 | " #sample prob distribution for next character\n",
305 | " c = torch.multinomial(probs,1)\n",
306 | " input_tensor = torch.cat([input_tensor[:,1:], c[None]], dim=1)\n",
307 | " input_sequence.append(c.item())\n",
308 | "\n",
309 | " return input_sequence"
310 | ],
311 | "execution_count": null,
312 | "outputs": []
313 | },
314 | {
315 | "cell_type": "code",
316 | "metadata": {
317 | "id": "GqjlxHyTHdhl",
318 | "cellView": "form"
319 | },
320 | "source": [
321 | "#@title Generate Output\n",
322 | "import uuid\n",
323 | "import torch\n",
324 | "from torch import nn\n",
325 | "torch.set_default_tensor_type(torch.cuda.FloatTensor)\n",
326 | "device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
327 | "print(device)\n",
328 | "from model import MusicTransformer\n",
329 | "from preprocess import SequenceEncoder\n",
330 | "import midi_input\n",
331 | "\n",
332 | "\n",
333 | "class GeneratorError(Exception):\n",
334 | " pass\n",
335 | "\n",
336 | "model_key = ''\n",
337 | "\n",
338 | " \n",
339 | "n_velocity_events = 32\n",
340 | "n_time_shift_events = 125\n",
341 | "\n",
342 | "decoder = SequenceEncoder(n_time_shift_events, n_velocity_events,\n",
343 | " min_events=0)\n",
344 | "\n",
345 | "prime_sequence = []\n",
346 | "\n",
347 | "\n",
348 | "\n",
349 | "temp = 0.4\n",
350 | "\n",
351 | "trial_key = str(uuid.uuid4())[:6]\n",
352 | "n_trials = 1\n",
353 | "\n",
354 | "sample_l = 2048\n",
355 | "\n",
356 | "keep_g = False\n",
357 | "stuck_note_d = None\n",
358 | "note_sequence = []\n",
359 | "\n",
360 | "\n",
361 | "for i in range(n_trials):\n",
362 | " print(\"generating sequence\")\n",
363 | " output_sequence = sample(transformer, prime_sequence = prime_sequence, sample_length=sample_l, temperature=temp)\n",
364 | " note_sequence = decoder.decode_sequence(output_sequence, \n",
365 | " verbose=True, stuck_note_duration=stuck_note_d, keep_ghosts=keep_g)\n",
366 | "\n",
367 | " output_dir = \"/content/pno-ai\"\n",
368 | " write_midi(note_sequence, output_dir, 'output')"
369 | ],
370 | "execution_count": null,
371 | "outputs": []
372 | }
373 | ]
374 | }
--------------------------------------------------------------------------------
/Super_Piano_6_Performer_GPU.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "Performer-Pytorch.ipynb",
7 | "private_outputs": true,
8 | "provenance": [],
9 | "collapsed_sections": [],
10 | "machine_shape": "hm",
11 | "authorship_tag": "ABX9TyNMiBCV+zp01Da43Z4AVlup",
12 | "include_colab_link": true
13 | },
14 | "kernelspec": {
15 | "name": "python3",
16 | "display_name": "Python 3"
17 | },
18 | "accelerator": "GPU"
19 | },
20 | "cells": [
21 | {
22 | "cell_type": "markdown",
23 | "metadata": {
24 | "id": "view-in-github",
25 | "colab_type": "text"
26 | },
27 | "source": [
28 | "
"
29 | ]
30 | },
31 | {
32 | "cell_type": "markdown",
33 | "metadata": {
34 | "id": "Ii5xWJ1sRc6x"
35 | },
36 | "source": [
37 | "https://github.com/lucidrains/performer-pytorch"
38 | ]
39 | },
40 | {
41 | "cell_type": "code",
42 | "metadata": {
43 | "id": "2mfyXs8qBTFA"
44 | },
45 | "source": [
46 | "!pip install performer-pytorch\r\n"
47 | ],
48 | "execution_count": null,
49 | "outputs": []
50 | },
51 | {
52 | "cell_type": "code",
53 | "metadata": {
54 | "id": "W7XQB1KbKPrE"
55 | },
56 | "source": [
57 | "%%writefile setup.sh \r\n",
58 | "\r\n",
59 | "# install apex to be able to use mix precision\r\n",
60 | "export CUDA_HOME=/usr/local/cuda-10.1\r\n",
61 | "git clone https://github.com/NVIDIA/apex\r\n",
62 | "pip install -v -q --no-cache-dir --global-option=\"--cpp_ext\" --global-option=\"--cuda_ext\" ./apex"
63 | ],
64 | "execution_count": null,
65 | "outputs": []
66 | },
67 | {
68 | "cell_type": "code",
69 | "metadata": {
70 | "id": "-UND0x9oKQhN"
71 | },
72 | "source": [
73 | "!sh setup.sh"
74 | ],
75 | "execution_count": null,
76 | "outputs": []
77 | },
78 | {
79 | "cell_type": "code",
80 | "metadata": {
81 | "id": "jDx1DeBNBNs7"
82 | },
83 | "source": [
84 | "from performer_pytorch import PerformerLM\r\n",
85 | "from performer_pytorch.autoregressive_wrapper import AutoregressiveWrapper\r\n",
86 | "\r\n",
87 | "import random\r\n",
88 | "import tqdm\r\n",
89 | "import gzip\r\n",
90 | "import numpy as np\r\n",
91 | "import torch\r\n",
92 | "import torch.optim as optim\r\n",
93 | "from torch.nn import functional as F\r\n",
94 | "from torch.utils.data import DataLoader, Dataset\r\n",
95 | "from torch.cuda.amp import autocast, GradScaler"
96 | ],
97 | "execution_count": null,
98 | "outputs": []
99 | },
100 | {
101 | "cell_type": "code",
102 | "metadata": {
103 | "id": "yi-8-u0IBBjp"
104 | },
105 | "source": [
106 | "# constants\r\n",
107 | "\r\n",
108 | "NUM_BATCHES = int(1e5)\r\n",
109 | "BATCH_SIZE = 16\r\n",
110 | "GRADIENT_ACCUMULATE_EVERY = 4\r\n",
111 | "LEARNING_RATE = 1e-4\r\n",
112 | "VALIDATE_EVERY = 100\r\n",
113 | "GENERATE_EVERY = 500\r\n",
114 | "GENERATE_LENGTH = 4096\r\n",
115 | "SEQ_LEN = 4096\r\n",
116 | "\r\n",
117 | "# helpers\r\n",
118 | "\r\n",
119 | "def cycle(loader):\r\n",
120 | " while True:\r\n",
121 | " for data in loader:\r\n",
122 | " yield data\r\n",
123 | "\r\n",
124 | "def decode_token(token):\r\n",
125 | " return str(chr(max(32, token)))\r\n",
126 | "\r\n",
127 | "def decode_tokens(tokens):\r\n",
128 | " return ''.join(list(map(decode_token, tokens)))\r\n",
129 | "\r\n",
130 | "# instantiate model\r\n",
131 | "\r\n",
132 | "model = PerformerLM(\r\n",
133 | " num_tokens = 256,\r\n",
134 | " dim = 512,\r\n",
135 | " depth = 6,\r\n",
136 | " max_seq_len = SEQ_LEN,\r\n",
137 | " heads = 8,\r\n",
138 | " causal = True,\r\n",
139 | " reversible = True,\r\n",
140 | " nb_features = 256,\r\n",
141 | " use_scalenorm = True,\r\n",
142 | " local_attn_heads = (8, 8, 8, 6, 4, 2)\r\n",
143 | ")\r\n",
144 | "\r\n",
145 | "model = AutoregressiveWrapper(model)\r\n",
146 | "model.cuda()"
147 | ],
148 | "execution_count": null,
149 | "outputs": []
150 | },
151 | {
152 | "cell_type": "code",
153 | "metadata": {
154 | "id": "S0YzpbD5ClFh"
155 | },
156 | "source": [
157 | "# prepare music data\r\n",
158 | "\r\n",
159 | "with open('/content/INT_DATASET.TXT') as file:\r\n",
160 | " X = np.fromstring(file.read(int(3e6)), dtype=np.uint8)\r\n",
161 | " trX, vaX = np.split(X, [int(2e6)])\r\n",
162 | " data_train, data_val = torch.from_numpy(trX), torch.from_numpy(vaX)"
163 | ],
164 | "execution_count": null,
165 | "outputs": []
166 | },
167 | {
168 | "cell_type": "code",
169 | "metadata": {
170 | "id": "yMEjUQapComn"
171 | },
172 | "source": [
173 | "class TextSamplerDataset(Dataset):\r\n",
174 | " def __init__(self, data, seq_len):\r\n",
175 | " super().__init__()\r\n",
176 | " self.data = data\r\n",
177 | " self.seq_len = seq_len\r\n",
178 | "\r\n",
179 | " def __getitem__(self, index):\r\n",
180 | " rand_start = torch.randint(0, self.data.size(0) - self.seq_len - 1, (1,))\r\n",
181 | " full_seq = self.data[rand_start: rand_start + self.seq_len + 1].long()\r\n",
182 | " return full_seq.cuda()\r\n",
183 | "\r\n",
184 | " def __len__(self):\r\n",
185 | " return self.data.size(0) // self.seq_len\r\n",
186 | "\r\n",
187 | "train_dataset = TextSamplerDataset(data_train, SEQ_LEN)\r\n",
188 | "val_dataset = TextSamplerDataset(data_val, SEQ_LEN)\r\n",
189 | "train_loader = cycle(DataLoader(train_dataset, batch_size = BATCH_SIZE))\r\n",
190 | "val_loader = cycle(DataLoader(val_dataset, batch_size = BATCH_SIZE))\r\n",
191 | "\r\n",
192 | "# optimizer\r\n",
193 | "\r\n",
194 | "optim = torch.optim.Adam(model.parameters(), lr=LEARNING_RATE)\r\n",
195 | "scaler = GradScaler()"
196 | ],
197 | "execution_count": null,
198 | "outputs": []
199 | },
200 | {
201 | "cell_type": "code",
202 | "metadata": {
203 | "id": "RGMJN1DrCwqg"
204 | },
205 | "source": [
206 | "# training\r\n",
207 | "\r\n",
208 | "for i in tqdm.tqdm(range(NUM_BATCHES), mininterval=10., desc='training'):\r\n",
209 | " model.train()\r\n",
210 | "\r\n",
211 | " for __ in range(GRADIENT_ACCUMULATE_EVERY):\r\n",
212 | " with autocast():\r\n",
213 | " loss = model(next(train_loader), return_loss = True)\r\n",
214 | " scaler.scale(loss).backward()\r\n",
215 | "\r\n",
216 | " print(f'training loss: {loss.item()}')\r\n",
217 | "\r\n",
218 | " scaler.unscale_(optim)\r\n",
219 | " torch.nn.utils.clip_grad_norm_(model.parameters(), 0.5)\r\n",
220 | " scaler.step(optim)\r\n",
221 | " scaler.update()\r\n",
222 | " optim.zero_grad()\r\n",
223 | "\r\n",
224 | " if i % VALIDATE_EVERY == 0:\r\n",
225 | " model.eval()\r\n",
226 | " with torch.no_grad():\r\n",
227 | " loss = model(next(val_loader), return_loss = True)\r\n",
228 | " print(f'validation loss: {loss.item()}')\r\n",
229 | "\r\n",
230 | " if i % GENERATE_EVERY == 0 and i != 0:\r\n",
231 | " model.eval()\r\n",
232 | " inp = random.choice(val_dataset)[:-1]\r\n",
233 | " prime = decode_tokens(inp)\r\n",
234 | " print(f'%s \\n\\n %s', (prime, '*' * 100))\r\n",
235 | "\r\n",
236 | " sample = model.generate(inp, GENERATE_LENGTH)\r\n",
237 | " output_str = decode_tokens(sample)\r\n",
238 | " print(output_str)"
239 | ],
240 | "execution_count": null,
241 | "outputs": []
242 | },
243 | {
244 | "cell_type": "code",
245 | "metadata": {
246 | "id": "ML6iQwFhGXES"
247 | },
248 | "source": [
249 | "model.eval()\r\n",
250 | "inp = random.choice(val_dataset)[:-1]\r\n",
251 | "prime = decode_tokens(inp)\r\n",
252 | "print(f'%s \\n\\n %s', (prime, '*' * 100))\r\n",
253 | "\r\n",
254 | "sample = model.generate(inp, GENERATE_LENGTH)\r\n",
255 | "output_str = decode_tokens(sample)\r\n",
256 | "print(output_str)"
257 | ],
258 | "execution_count": null,
259 | "outputs": []
260 | }
261 | ]
262 | }
--------------------------------------------------------------------------------
/[TMIDI]_Super_Piano_3.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "[TMIDI] Super_Piano_3.ipynb",
7 | "private_outputs": true,
8 | "provenance": [],
9 | "collapsed_sections": [],
10 | "machine_shape": "hm",
11 | "include_colab_link": true
12 | },
13 | "kernelspec": {
14 | "name": "python3",
15 | "display_name": "Python 3"
16 | },
17 | "accelerator": "GPU"
18 | },
19 | "cells": [
20 | {
21 | "cell_type": "markdown",
22 | "metadata": {
23 | "id": "view-in-github",
24 | "colab_type": "text"
25 | },
26 | "source": [
27 | "
"
28 | ]
29 | },
30 | {
31 | "cell_type": "markdown",
32 | "metadata": {
33 | "id": "9opKSK2RSDRg"
34 | },
35 | "source": [
36 | "# Super Piano 3: Google Music Transformer Reproduction\n",
37 | "\n",
38 | "## Generating Music with Long-Term structure\n",
39 | "\n",
40 | "## Powered by TMIDI 2.0. Optimus Processors\n",
41 | "## https://github.com/asigalov61/tegridy-tools\n",
42 | "\n",
43 | "### Based on 2019 ICLR paper by Cheng-Zhi Anna Huang, Google Brain and Damon Gwinn's code/repo https://github.com/gwinndr/MusicTransformer-Pytorch\n"
44 | ]
45 | },
46 | {
47 | "cell_type": "markdown",
48 | "metadata": {
49 | "id": "05hD19W0hSCP"
50 | },
51 | "source": [
52 | "###Setup Environment and Dependencies. Check GPU."
53 | ]
54 | },
55 | {
56 | "cell_type": "code",
57 | "metadata": {
58 | "id": "Ror_UJUp7wlO",
59 | "cellView": "form"
60 | },
61 | "source": [
62 | "#@title Check if GPU (driver) is avaiiable (you do not want to run this on CPU, trust me)\n",
63 | "!nvcc --version\n",
64 | "!nvidia-smi"
65 | ],
66 | "execution_count": null,
67 | "outputs": []
68 | },
69 | {
70 | "cell_type": "code",
71 | "metadata": {
72 | "id": "paYvoZHihtux",
73 | "cellView": "form"
74 | },
75 | "source": [
76 | "#@title Clone/Install all dependencies\n",
77 | "!git clone https://github.com/asigalov61/MusicTransformer-Pytorch\n",
78 | "!git clone https://github.com/asigalov61/tegridy-tools\n",
79 | "!cp /content/tegridy-tools/tegridy-tools/TMIDI.py /content/MusicTransformer-Pytorch\n",
80 | "\n",
81 | "!pip install tqdm\n",
82 | "!pip install progress\n",
83 | "!pip install pretty-midi\n",
84 | "!pip install pypianoroll\n",
85 | "!pip install matplotlib\n",
86 | "!pip install librosa\n",
87 | "!pip install scipy\n",
88 | "!pip install pillow\n",
89 | "!apt install fluidsynth #Pip does not work for some reason. Only apt works\n",
90 | "!pip install midi2audio\n",
91 | "!pip install mir_eval\n",
92 | "!cp /usr/share/sounds/sf2/FluidR3_GM.sf2 /content/font.sf2"
93 | ],
94 | "execution_count": null,
95 | "outputs": []
96 | },
97 | {
98 | "cell_type": "code",
99 | "metadata": {
100 | "id": "VM71tUPVfffi",
101 | "cellView": "form"
102 | },
103 | "source": [
104 | "#@title Import all needed modules\n",
105 | "%cd /content/tegridy-tools/tegridy-tools/\n",
106 | "import TMIDI\n",
107 | "%cd /content/\n",
108 | "\n",
109 | "import numpy as np\n",
110 | "import pickle\n",
111 | "import os\n",
112 | "import sys\n",
113 | "import math\n",
114 | "import random\n",
115 | "\n",
116 | "# For plotting\n",
117 | "import pypianoroll\n",
118 | "from pypianoroll import Multitrack, Track\n",
119 | "import matplotlib\n",
120 | "import matplotlib.pyplot as plt\n",
121 | "%matplotlib inline\n",
122 | "import mir_eval.display\n",
123 | "import librosa\n",
124 | "import librosa.display\n",
125 | "\n",
126 | "# For rendering output audio\n",
127 | "import pretty_midi\n",
128 | "from midi2audio import FluidSynth\n",
129 | "from google.colab import output\n",
130 | "from IPython.display import display, Javascript, HTML, Audio"
131 | ],
132 | "execution_count": null,
133 | "outputs": []
134 | },
135 | {
136 | "cell_type": "markdown",
137 | "metadata": {
138 | "id": "XKz4SKoeXYWc"
139 | },
140 | "source": [
141 | "# Process your own custom MIDI DataSet"
142 | ]
143 | },
144 | {
145 | "cell_type": "code",
146 | "metadata": {
147 | "id": "KUXaozztvGU2",
148 | "cellView": "form"
149 | },
150 | "source": [
151 | "#@title Upload your custom MIDI DataSet to created \"dataset/e_piano/custom_midis\" folder through this cell or manually through any other means. You can also use the dataset below.\n",
152 | "from google.colab import files\n",
153 | "%cd '/content/MusicTransformer-Pytorch/dataset/e_piano/custom_midis'\n",
154 | "uploaded = files.upload()\n",
155 | "\n",
156 | "for fn in uploaded.keys():\n",
157 | " print('User uploaded file \"{name}\" with length {length} bytes'.format(\n",
158 | " name=fn, length=len(uploaded[fn])))"
159 | ],
160 | "execution_count": null,
161 | "outputs": []
162 | },
163 | {
164 | "cell_type": "code",
165 | "metadata": {
166 | "id": "uDsmK-vkwOgl",
167 | "cellView": "form"
168 | },
169 | "source": [
170 | "#@title Tegridy Piano Dataset (~230 Modern Piano MIDIs)\n",
171 | "%cd /content/MusicTransformer-Pytorch/dataset/e_piano/custom_midis\n",
172 | "!wget 'https://github.com/asigalov61/Tegridy-MIDI-Dataset/raw/master/Tegridy-Piano-CC-BY-NC-SA.zip'\n",
173 | "!unzip -j 'Tegridy-Piano-CC-BY-NC-SA.zip'\n",
174 | "!rm Tegridy-Piano-CC-BY-NC-SA.zip"
175 | ],
176 | "execution_count": null,
177 | "outputs": []
178 | },
179 | {
180 | "cell_type": "markdown",
181 | "metadata": {
182 | "id": "e-jAV_Qv5Fn_"
183 | },
184 | "source": [
185 | "For now, we are going to split the dataset by random into \"test\"/\"val\" dirs which is not ideal. So feel free to modify the code to your liking to achieve better training results with this implementation."
186 | ]
187 | },
188 | {
189 | "cell_type": "code",
190 | "metadata": {
191 | "id": "IZ5c6d5lXemo",
192 | "cellView": "form"
193 | },
194 | "source": [
195 | "#@title Process your custom MIDI DataSet :)\n",
196 | "%cd /content/\n",
197 | "import TMIDI\n",
198 | "\n",
199 | "%cd /content/MusicTransformer-Pytorch\n",
200 | "\n",
201 | "import os\n",
202 | "import random\n",
203 | "\n",
204 | "%cd '/content/MusicTransformer-Pytorch/dataset/e_piano/custom_midis'\n",
205 | "\n",
206 | "custom_MIDI_DataSet_dir = '/content/MusicTransformer-Pytorch/dataset/e_piano/custom_midis'\n",
207 | "\n",
208 | "train_dir = '/content/MusicTransformer-Pytorch/dataset/e_piano/train' # split_type = 0\n",
209 | "test_dir = '/content/MusicTransformer-Pytorch/dataset/e_piano/test' # split_type = 1 \n",
210 | "val_dir = '/content/MusicTransformer-Pytorch/dataset/e_piano/val' # split_type = 2\n",
211 | "\n",
212 | "decoding_dictionary = {}\n",
213 | "All_INTs = []\n",
214 | "total_count = 0\n",
215 | "train_count = 0\n",
216 | "val_count = 0\n",
217 | "test_count = 0\n",
218 | "\n",
219 | "prp = []\n",
220 | "npi = 0\n",
221 | "nsi = 0\n",
222 | "\n",
223 | "f_ext = '.pickle'\n",
224 | "fileList = os.listdir(custom_MIDI_DataSet_dir)\n",
225 | "for file in fileList:\n",
226 | " # we gonna split by a random selection for now\n",
227 | " \n",
228 | " split = random.randint(1, 2)\n",
229 | " if (split == 0):\n",
230 | " o_file = os.path.join(train_dir, file+f_ext)\n",
231 | " train_count += 1\n",
232 | "\n",
233 | " elif (split == 2):\n",
234 | " o_file0 = os.path.join(train_dir, file+f_ext)\n",
235 | " train_count += 1\n",
236 | " o_file = os.path.join(val_dir, file+f_ext)\n",
237 | " val_count += 1\n",
238 | "\n",
239 | " elif (split == 1):\n",
240 | " o_file0 = os.path.join(train_dir, file+f_ext)\n",
241 | " train_count += 1\n",
242 | " o_file = os.path.join(test_dir, file+f_ext)\n",
243 | " test_count += 1\n",
244 | " \n",
245 | " try:\n",
246 | " \n",
247 | " desired_MIDI_channel_to_process = 0 \n",
248 | " MIDI_events_time_denominator = 10\n",
249 | " melody_notes_in_chords = True\n",
250 | "\n",
251 | " '''chords_list, melody = TMIDI.Tegridy_MIDI_Processor(file, \n",
252 | " desired_MIDI_channel_to_process, \n",
253 | " MIDI_events_time_denominator,\n",
254 | " )'''\n",
255 | " fn = os.path.basename(file)\n",
256 | " fno = fn.split('.')[0].replace(' ', '_')\n",
257 | "\n",
258 | " '''chords_l, melody_l = TMIDI.Tegridy_Chords_Converter(chords_list, \n",
259 | " melody, \n",
260 | " fno) \n",
261 | " line_by_line_dataset = True\n",
262 | " represent_events_every_nth_chord = 0\n",
263 | " chords_durations_multiplier = 1\n",
264 | " chords_beat_divider = 10\n",
265 | " pad_chords_with_rests = False\n",
266 | " simulate_velocity = True\n",
267 | " \n",
268 | " TXT, number_of_chords, number_of_bad_chords = TMIDI.Tegridy_MIDI_TXT_Processor('Tegridy Dataset', \n",
269 | " chords_l, \n",
270 | " melody_l, \n",
271 | " simulate_velocity, \n",
272 | " line_by_line_dataset,\n",
273 | " represent_events_every_nth_chord,\n",
274 | " chords_durations_multiplier,\n",
275 | " pad_chords_with_rests,\n",
276 | " chords_beat_divider)\n",
277 | "\n",
278 | " TXT1, count = TMIDI.Tegridy_TXT_Reducer(TXT, include_MIDI_channels=False, include_notes_velocities=False)'''\n",
279 | " desired_MIDI_channel_to_process = 0\n",
280 | " encode_velocities = True\n",
281 | " chordify_input_MIDIs = False\n",
282 | " time_denominator = 10\n",
283 | " chars_encoding_offset = 33\n",
284 | "\n",
285 | " \n",
286 | " TXT1, melody, chords = TMIDI.Optimus_MIDI_TXT_Processor(file, \n",
287 | " chordify_TXT=chordify_input_MIDIs, \n",
288 | " output_MIDI_channels=False, \n",
289 | " char_offset=chars_encoding_offset, \n",
290 | " dataset_MIDI_events_time_denominator=time_denominator,\n",
291 | " output_velocity=encode_velocities, \n",
292 | " MIDI_channel=desired_MIDI_channel_to_process) \n",
293 | " prepped, prepped_str, np, ns = TMIDI.Tegridy_TXT_to_INT_Converter(TXT1, max_INT=387)\n",
294 | " \n",
295 | " npi += np\n",
296 | " nsi += ns\n",
297 | " \n",
298 | " All_INTs.extend(prepped)\n",
299 | "\n",
300 | " o_stream = open(o_file0, \"wb\")\n",
301 | " pickle.dump(prepped, o_stream)\n",
302 | " o_stream.close()\n",
303 | "\n",
304 | " o_stream = open(o_file, \"wb\")\n",
305 | " pickle.dump(prepped, o_stream)\n",
306 | " o_stream.close()\n",
307 | " \n",
308 | " print(file)\n",
309 | " print(o_file)\n",
310 | " print('Coverted!')\n",
311 | "\n",
312 | " except KeyboardInterrupt: \n",
313 | " raise \n",
314 | " except:\n",
315 | " print('Bad file. Skipping...', file)\n",
316 | " continue\n",
317 | "\n",
318 | "print('Done')\n",
319 | "print(\"Num Train:\", train_count)\n",
320 | "print(\"Num Val:\", val_count)\n",
321 | "print(\"Num Test:\", test_count)\n",
322 | "print(\"Total Count:\", train_count)\n",
323 | "\n",
324 | "%cd /content/MusicTransformer-Pytorch"
325 | ],
326 | "execution_count": null,
327 | "outputs": []
328 | },
329 | {
330 | "cell_type": "markdown",
331 | "metadata": {
332 | "id": "JwCQIziNwHxe"
333 | },
334 | "source": [
335 | "#Train the Model"
336 | ]
337 | },
338 | {
339 | "cell_type": "code",
340 | "metadata": {
341 | "id": "hwisXl2Iy_Xf",
342 | "cellView": "form"
343 | },
344 | "source": [
345 | "#@title Activate Tensorboard Graphs/Stats to monitor/evaluate model perfomance during and after training runs\n",
346 | "# Load the TensorBoard notebook extension\n",
347 | "%reload_ext tensorboard\n",
348 | "import tensorflow as tf\n",
349 | "import datetime, os\n",
350 | "%tensorboard --logdir /content/MusicTransformer-Pytorch/rpr"
351 | ],
352 | "execution_count": null,
353 | "outputs": []
354 | },
355 | {
356 | "cell_type": "code",
357 | "metadata": {
358 | "id": "Sbv_sJyLq5om",
359 | "cellView": "form"
360 | },
361 | "source": [
362 | "#@title Start to Train the Model\n",
363 | "batch_size = 4 #@param {type:\"slider\", min:2, max:16, step:2}\n",
364 | "number_of_training_epochs = 300 #@param {type:\"slider\", min:10, max:600, step:10}\n",
365 | "maximum_output_MIDI_sequence = 2048 #@param {type:\"slider\", min:0, max:8192, step:128}\n",
366 | "!python3 train.py -output_dir rpr --rpr -batch_size=$batch_size -epochs=$number_of_training_epochs -max_sequence=$maximum_output_MIDI_sequence #-n_layers -num_heads -d_model -dim_feedforward"
367 | ],
368 | "execution_count": null,
369 | "outputs": []
370 | },
371 | {
372 | "cell_type": "code",
373 | "metadata": {
374 | "id": "9VLdhokSGUAu",
375 | "cellView": "form"
376 | },
377 | "source": [
378 | "#@title Re-Start Training from a certain checkpoint and epoch\n",
379 | "batch_size = 4 #@param {type:\"slider\", min:2, max:16, step:2}\n",
380 | "number_of_training_epochs = 400 #@param {type:\"slider\", min:10, max:600, step:10}\n",
381 | "maximum_output_MIDI_sequence = 2048 #@param {type:\"slider\", min:128, max:8192, step:128}\n",
382 | "saved_checkpoint_full_path = \"/content/MusicTransformer-Pytorch/rpr/weights/epoch_0145.pickle\" #@param {type:\"string\"}\n",
383 | "continue_epoch_number = 145 #@param {type:\"integer\"}\n",
384 | "\n",
385 | "!python3 train.py -output_dir rpr --rpr -batch_size=$batch_size -epochs=$number_of_training_epochs -max_sequence=$maximum_output_MIDI_sequence -continue_weights $saved_checkpoint_full_path -continue_epoch $continue_epoch_number #-n_layers -num_heads -d_model -dim_feedforward"
386 | ],
387 | "execution_count": null,
388 | "outputs": []
389 | },
390 | {
391 | "cell_type": "markdown",
392 | "metadata": {
393 | "id": "k1D-o-E-TnI8"
394 | },
395 | "source": [
396 | "###Evaluate the resulted models"
397 | ]
398 | },
399 | {
400 | "cell_type": "code",
401 | "metadata": {
402 | "id": "MusrrrOxt1uy",
403 | "cellView": "form"
404 | },
405 | "source": [
406 | "#@title Graph the results\n",
407 | "import argparse\n",
408 | "import os\n",
409 | "import csv\n",
410 | "import math\n",
411 | "import matplotlib.pyplot as plt\n",
412 | "\n",
413 | "RESULTS_FILE = \"results.csv\"\n",
414 | "EPOCH_IDX = 0\n",
415 | "LR_IDX = 1\n",
416 | "EVAL_LOSS_IDX = 4\n",
417 | "EVAL_ACC_IDX = 5\n",
418 | "\n",
419 | "SPLITTER = '?'\n",
420 | "\n",
421 | "\n",
422 | "def graph_results(input_dirs=\"/content/MusicTransformer-Pytorch/rpr/results\", output_dir=None, model_names=None, epoch_start=0, epoch_end=None):\n",
423 | " \"\"\"\n",
424 | " ----------\n",
425 | " Author: Damon Gwinn\n",
426 | " ----------\n",
427 | " Graphs model training and evaluation data\n",
428 | " ----------\n",
429 | " \"\"\"\n",
430 | "\n",
431 | " input_dirs = input_dirs.split(SPLITTER)\n",
432 | "\n",
433 | " if(model_names is not None):\n",
434 | " model_names = model_names.split(SPLITTER)\n",
435 | " if(len(model_names) != len(input_dirs)):\n",
436 | " print(\"Error: len(model_names) != len(input_dirs)\")\n",
437 | " return\n",
438 | "\n",
439 | " #Initialize Loss and Accuracy arrays\n",
440 | " loss_arrs = []\n",
441 | " accuracy_arrs = []\n",
442 | " epoch_counts = []\n",
443 | " lrs = []\n",
444 | "\n",
445 | " for input_dir in input_dirs:\n",
446 | " loss_arr = []\n",
447 | " accuracy_arr = []\n",
448 | " epoch_count = []\n",
449 | " lr_arr = []\n",
450 | "\n",
451 | " f = os.path.join(input_dir, RESULTS_FILE)\n",
452 | " with open(f, \"r\") as i_stream:\n",
453 | " reader = csv.reader(i_stream)\n",
454 | " next(reader)\n",
455 | "\n",
456 | " lines = [line for line in reader]\n",
457 | "\n",
458 | " if(epoch_end is None):\n",
459 | " epoch_end = math.inf\n",
460 | "\n",
461 | " epoch_start = max(epoch_start, 0)\n",
462 | " epoch_start = min(epoch_start, epoch_end)\n",
463 | "\n",
464 | " for line in lines:\n",
465 | " epoch = line[EPOCH_IDX]\n",
466 | " lr = line[LR_IDX]\n",
467 | " accuracy = line[EVAL_ACC_IDX]\n",
468 | " loss = line[EVAL_LOSS_IDX]\n",
469 | "\n",
470 | " if(int(epoch) >= epoch_start and int(epoch) < epoch_end):\n",
471 | " accuracy_arr.append(float(accuracy))\n",
472 | " loss_arr.append(float(loss))\n",
473 | " epoch_count.append(int(epoch))\n",
474 | " lr_arr.append(float(lr))\n",
475 | "\n",
476 | " loss_arrs.append(loss_arr)\n",
477 | " accuracy_arrs.append(accuracy_arr)\n",
478 | " epoch_counts.append(epoch_count)\n",
479 | " lrs.append(lr_arr)\n",
480 | "\n",
481 | " if(output_dir is not None):\n",
482 | " try:\n",
483 | " os.mkdir(output_dir)\n",
484 | " except OSError:\n",
485 | " print (\"Creation of the directory %s failed\" % output_dir)\n",
486 | " else:\n",
487 | " print (\"Successfully created the directory %s\" % output_dir)\n",
488 | "\n",
489 | " ##### LOSS #####\n",
490 | " for i in range(len(loss_arrs)):\n",
491 | " if(model_names is None):\n",
492 | " name = None\n",
493 | " else:\n",
494 | " name = model_names[i]\n",
495 | "\n",
496 | " #Create and save plots to output folder\n",
497 | " plt.plot(epoch_counts[i], loss_arrs[i], label=name)\n",
498 | " plt.title(\"Loss Results\")\n",
499 | " plt.ylabel('Loss (Cross Entropy)')\n",
500 | " plt.xlabel('Epochs')\n",
501 | " fig1 = plt.gcf()\n",
502 | "\n",
503 | " plt.legend(loc=\"upper left\")\n",
504 | "\n",
505 | " if(output_dir is not None):\n",
506 | " fig1.savefig(os.path.join(output_dir, 'loss_graph.png'))\n",
507 | "\n",
508 | " plt.show()\n",
509 | "\n",
510 | " ##### ACCURACY #####\n",
511 | " for i in range(len(accuracy_arrs)):\n",
512 | " if(model_names is None):\n",
513 | " name = None\n",
514 | " else:\n",
515 | " name = model_names[i]\n",
516 | "\n",
517 | " #Create and save plots to output folder\n",
518 | " plt.plot(epoch_counts[i], accuracy_arrs[i], label=name)\n",
519 | " plt.title(\"Accuracy Results\")\n",
520 | " plt.ylabel('Accuracy')\n",
521 | " plt.xlabel('Epochs')\n",
522 | " fig2 = plt.gcf()\n",
523 | "\n",
524 | " plt.legend(loc=\"upper left\")\n",
525 | "\n",
526 | " if(output_dir is not None):\n",
527 | " fig2.savefig(os.path.join(output_dir, 'accuracy_graph.png'))\n",
528 | "\n",
529 | " plt.show()\n",
530 | "\n",
531 | " ##### LR #####\n",
532 | " for i in range(len(lrs)):\n",
533 | " if(model_names is None):\n",
534 | " name = None\n",
535 | " else:\n",
536 | " name = model_names[i]\n",
537 | "\n",
538 | " #Create and save plots to output folder\n",
539 | " plt.plot(epoch_counts[i], lrs[i], label=name)\n",
540 | " plt.title(\"Learn Rate Results\")\n",
541 | " plt.ylabel('Learn Rate')\n",
542 | " plt.xlabel('Epochs')\n",
543 | " fig2 = plt.gcf()\n",
544 | "\n",
545 | " plt.legend(loc=\"upper left\")\n",
546 | "\n",
547 | " if(output_dir is not None):\n",
548 | " fig2.savefig(os.path.join(output_dir, 'lr_graph.png'))\n",
549 | "\n",
550 | " plt.show()\n",
551 | "graph_results('/content/MusicTransformer-Pytorch/rpr/results', model_names='rpr')"
552 | ],
553 | "execution_count": null,
554 | "outputs": []
555 | },
556 | {
557 | "cell_type": "markdown",
558 | "metadata": {
559 | "id": "fxHrTsFUdn-r"
560 | },
561 | "source": [
562 | "To have the model continue your custom MIDI enter the following into the custom_MIDI field below:\n",
563 | "\n",
564 | "-primer_file '/content/some_dir/some_seed_midi.mid'\n",
565 | "\n",
566 | "For example: -primer_file '/content/MusicTransformer-Pytorch/seed.mid'"
567 | ]
568 | },
569 | {
570 | "cell_type": "markdown",
571 | "metadata": {
572 | "id": "EJXWoBMWL3ph"
573 | },
574 | "source": [
575 | "# Generate and Explore the output :)"
576 | ]
577 | },
578 | {
579 | "cell_type": "code",
580 | "metadata": {
581 | "id": "czNulONr4tB6",
582 | "cellView": "form"
583 | },
584 | "source": [
585 | "#@title Generate, Plot, Graph, Save, Download, and Render the resulting output\n",
586 | "number_of_tokens_to_generate = 2021 #@param {type:\"slider\", min:1, max:4096, step:1}\n",
587 | "priming_sequence_length = 3 #@param {type:\"slider\", min:1, max:100, step:1}\n",
588 | "maximum_possible_output_sequence = 2048 #@param {type:\"slider\", min:0, max:4096, step:8}\n",
589 | "select_model = \"/content/MusicTransformer-Pytorch/rpr/results/best_loss_weights.pickle\" #@param [\"/content/MusicTransformer-Pytorch/rpr/results/best_acc_weights.pickle\", \"/content/MusicTransformer-Pytorch/rpr/results/best_loss_weights.pickle\"]\n",
590 | "custom_MIDI = \"\" #@param {type:\"string\"}\n",
591 | "%cd /content/MusicTransformer-Pytorch\n",
592 | "#import processor\n",
593 | "#from processor import encode_midi, decode_midi\n",
594 | "\n",
595 | "!python generate_TMIDI.py -output_dir output -model_weights=$select_model --rpr -target_seq_length=$number_of_tokens_to_generate -num_prime=$priming_sequence_length -max_sequence=$maximum_possible_output_sequence $custom_MIDI #\n",
596 | "\n",
597 | "print('Successfully exported the output to output folder. To primer.mid and rand.mid')\n",
598 | "\n",
599 | "# set the src and play\n",
600 | "#FluidSynth(\"/content/font.sf2\").midi_to_audio('/content/MusicTransformer-Pytorch/output/rand.mid', '/content/MusicTransformer-Pytorch/output/output.wav')\n",
601 | "\n",
602 | "#from google.colab import files\n",
603 | "#files.download('/content/MusicTransformer-Pytorch/output/rand.mid')\n",
604 | "#files.download('/content/MusicTransformer-Pytorch/output/primer.mid')\n",
605 | "\n",
606 | "#Audio('/content/MusicTransformer-Pytorch/output/output.wav')\n"
607 | ],
608 | "execution_count": null,
609 | "outputs": []
610 | },
611 | {
612 | "cell_type": "code",
613 | "metadata": {
614 | "id": "IG48uyKGzcTI",
615 | "cellView": "form"
616 | },
617 | "source": [
618 | "#@title Plot and Graph the Output :)\n",
619 | "graphs_length_inches = 14 #@param {type:\"slider\", min:0, max:20, step:1}\n",
620 | "notes_graph_height = 10 #@param {type:\"slider\", min:0, max:20, step:1}\n",
621 | "highest_displayed_pitch = 92 #@param {type:\"slider\", min:1, max:128, step:1}\n",
622 | "lowest_displayed_pitch = 24 #@param {type:\"slider\", min:1, max:128, step:1}\n",
623 | "piano_roll_color_map = \"Blues\"\n",
624 | "\n",
625 | "import librosa\n",
626 | "import numpy as np\n",
627 | "import pretty_midi\n",
628 | "import pypianoroll\n",
629 | "from pypianoroll import Multitrack, Track\n",
630 | "import matplotlib\n",
631 | "import matplotlib.pyplot as plt\n",
632 | "#matplotlib.use('SVG')\n",
633 | "# For plotting\n",
634 | "import mir_eval.display\n",
635 | "import librosa.display\n",
636 | "%matplotlib inline\n",
637 | "\n",
638 | "\n",
639 | "midi_data = pretty_midi.PrettyMIDI('/content/MusicTransformer-Pytorch/output/rand.mid')\n",
640 | "\n",
641 | "def plot_piano_roll(pm, start_pitch, end_pitch, fs=100):\n",
642 | " # Use librosa's specshow function for displaying the piano roll\n",
643 | " librosa.display.specshow(pm.get_piano_roll(fs)[start_pitch:end_pitch],\n",
644 | " hop_length=1, sr=fs, x_axis='time', y_axis='cqt_note',\n",
645 | " fmin=pretty_midi.note_number_to_hz(start_pitch))\n",
646 | "\n",
647 | "\n",
648 | "\n",
649 | "# Plot the output\n",
650 | "fname = '/content/MusicTransformer-Pytorch/output/rand'\n",
651 | "plt.figure(figsize=(graphs_length_inches, notes_graph_height))\n",
652 | "ax2 = plot_piano_roll(midi_data, int(lowest_displayed_pitch), int(highest_displayed_pitch))\n",
653 | "\n",
654 | "plt.show(block=False)\n",
655 | "FluidSynth(\"/usr/share/sounds/sf2/FluidR3_GM.sf2\", 16000).midi_to_audio(str(fname + '.mid'), str(fname + '.wav'))\n",
656 | "Audio(str(fname + '.wav'), rate=16000)"
657 | ],
658 | "execution_count": null,
659 | "outputs": []
660 | }
661 | ]
662 | }
--------------------------------------------------------------------------------
/trained_model.h5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asigalov61/SuperPiano/83bfaccf50dcbc53349a389b60c37205b9d38162/trained_model.h5
--------------------------------------------------------------------------------
/trained_model_jazz.h5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asigalov61/SuperPiano/83bfaccf50dcbc53349a389b60c37205b9d38162/trained_model_jazz.h5
--------------------------------------------------------------------------------
/trained_model_piano.h5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/asigalov61/SuperPiano/83bfaccf50dcbc53349a389b60c37205b9d38162/trained_model_piano.h5
--------------------------------------------------------------------------------