diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..496ee2c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+.DS_Store
\ No newline at end of file
diff --git a/Lab 2/GAN.ipynb b/Lab 2/GAN.ipynb
new file mode 100644
index 0000000..b0c9246
--- /dev/null
+++ b/Lab 2/GAN.ipynb
@@ -0,0 +1,1187 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Introduction"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This tutorial is a brief introduction to music generation using **Generative Adversarial Networks** (**GAN**s). \n",
+ "\n",
+ "The goal of this tutorial is to train a machine learning model using a dataset of Bach compositions so that the model learns to add accompaniments to a single track input melody. In other words, if the user provides a single piano track of a song such as \"twinkle twinkle little star\", the GAN model would add three other piano tracks to make the music sound more Bach-inspired.\n",
+ "\n",
+ "The proposed algorithm consists of two competing networks: a generator and a critic (discriminator). A generator is a deep neural network that learns to create new synthetic data that resembles the distribution of the dataset on which it was trained. A critic is another deep neural network that is trained to differentiate between real and synthetic data. The generator and the critic are trained in alternating cycles such that the generator learns to produce more and more realistic data (Bach-like music in this use case) while the critic iteratively gets better at learning to differentiate real data (Bach music) from the synthetic ones.\n",
+ "\n",
+ "As a result, the quality of music produced by the generator gets more and more realistic with time."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Dependencies\n",
+ "First, let's import all of the python packages we will use throughout the tutorial.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n",
+ "\n",
+ "# Permission is hereby granted, free of charge, to any person obtaining a copy of\n",
+ "# this software and associated documentation files (the \"Software\"), to deal in\n",
+ "# the Software without restriction, including without limitation the rights to\n",
+ "# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\n",
+ "# the Software, and to permit persons to whom the Software is furnished to do so.\n",
+ "\n",
+ "# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n",
+ "# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n",
+ "# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n",
+ "# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n",
+ "# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n",
+ "# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n",
+ "\n",
+ "\n",
+ "# Create the environment\n",
+ "!conda update --all --y \n",
+ "!pip install tensorflow-gpu==1.14.0\n",
+ "!pip install numpy==1.16.4\n",
+ "!pip install pretty_midi\n",
+ "!pip install pypianoroll\n",
+ "!pip install music21\n",
+ "!pip install seaborn\n",
+ "!pip install --ignore-installed moviepy"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# IMPORTS\n",
+ "import os \n",
+ "import numpy as np\n",
+ "from PIL import Image\n",
+ "import logging\n",
+ "import pypianoroll\n",
+ "import scipy.stats\n",
+ "import pickle\n",
+ "import music21\n",
+ "from IPython import display\n",
+ "import matplotlib.pyplot as plt\n",
+ "\n",
+ "# Configure Tensorflow\n",
+ "import tensorflow as tf\n",
+ "print(tf.__version__)\n",
+ "tf.logging.set_verbosity(tf.logging.ERROR)\n",
+ "tf.enable_eager_execution()\n",
+ "\n",
+ "# Use this command to make a subset of GPUS visible to the jupyter notebook.\n",
+ "os.environ['CUDA_VISIBLE_DEVICES'] = '0'\n",
+ "os.environ[\"CUDA_DEVICE_ORDER\"]=\"PCI_BUS_ID\"\n",
+ "\n",
+ "# Utils library for plotting, loading and saving midi among other functions\n",
+ "from utils import display_utils, metrics_utils, path_utils, inference_utils, midi_utils\n",
+ "\n",
+ "LOGGER = logging.getLogger(\"gan.train\")\n",
+ "%matplotlib inline"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Configuration"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Here we configure paths to retrieve our dataset and save our experiments."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "root_dir = './Experiments'\n",
+ "\n",
+ "# Directory to save checkpoints\n",
+ "model_dir = os.path.join(root_dir,'2Bar') # JSP: 229, Bach: 19199\n",
+ "\n",
+ "# Directory to save pianorolls during training\n",
+ "train_dir = os.path.join(model_dir, 'train')\n",
+ "\n",
+ "# Directory to save checkpoint generated during training\n",
+ "check_dir = os.path.join(model_dir, 'preload')\n",
+ "\n",
+ "# Directory to save midi during training\n",
+ "sample_dir = os.path.join(model_dir, 'sample')\n",
+ "\n",
+ "# Directory to save samples generated during inference\n",
+ "eval_dir = os.path.join(model_dir, 'eval')\n",
+ "\n",
+ "os.makedirs(train_dir, exist_ok=True)\n",
+ "os.makedirs(eval_dir, exist_ok=True)\n",
+ "os.makedirs(sample_dir, exist_ok=True)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Data Preparation\n",
+ "\n",
+ "### Dataset summary\n",
+ "\n",
+ "In this tutorial, we use the [`JSB-Chorales-dataset`](http://www-etud.iro.umontreal.ca/~boulanni/icml2012), comprising 229 chorale snippets. A chorale is a hymn that is usually sung with a single voice playing a simple melody and three lower voices providing harmony. In this dataset, these voices are represented by four piano tracks.\n",
+ "\n",
+ "Let's listen to a song from this dataset."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "display_utils.playmidi('./original_midi/MIDI-0.mid')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Data format - piano roll"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "For the purpose of this tutorial, we represent music from the JSB-Chorales dataset in the piano roll format.\n",
+ "\n",
+ "**Piano roll** is a discrete representation of music which is intelligible by many machine learning algorithms. Piano rolls can be viewed as a two-dimensional grid with \"Time\" on the horizontal axis and \"Pitch\" on the vertical axis. A one or zero in any particular cell in this grid indicates if a note was played or not at that time for that pitch.\n",
+ "\n",
+ "Let us look at a few piano rolls in our dataset. In this example, a single piano roll track has 32 discrete time steps and 128 pitches. We see four piano rolls here, each one representing a separate piano track in the song."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "\n",
+ "You might notice this representation looks similar to an image. While the sequence of notes is often the natural way that people view music, many modern machine learning models instead treat music as images and leverage existing techniques within the computer vision domain. You will see such techniques used in our architecture later in this tutorial."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Why 32 time steps?**\n",
+ "\n",
+ "For the purpose of this tutorial, we sample two non-empty bars (https://en.wikipedia.org/wiki/Bar_(music)) from each song in the JSB-Chorales dataset. A **bar** (or **measure**) is a unit of composition and contains four beats for songs in our particular dataset (our songs are all in 4/4 time) :\n",
+ "\n",
+ "We’ve found that using a resolution of four time steps per beat captures enough of the musical detail in this dataset.\n",
+ "\n",
+ "This yields...\n",
+ "\n",
+ "$$ \\frac{4\\;timesteps}{1\\;beat} * \\frac{4\\;beats}{1\\;bar} * \\frac{2\\;bars}{1} = 32\\;timesteps $$\n",
+ "\n",
+ "Let us now load our dataset as a numpy array. Our dataset comprises 229 samples of 4 tracks (all tracks are piano). Each sample is a 32 time-step snippet of a song, so our dataset has a shape of...\n",
+ "(num_samples, time_steps, pitch_range, tracks) = (229, 32, 128, 4)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "training_data = np.load('./dataset/train.npy')\n",
+ "print(training_data.shape)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Let's see a sample of the data we'll feed into our model. The four graphs represent the four tracks."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "display_utils.show_pianoroll(training_data)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Load data "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We now create a Tensorflow dataset object from our numpy array to feed into our model. The dataset object helps us feed batches of data into our model. A batch is a subset of the data that is passed through the deep learning network before the weights are updated. Batching data is necessary in most training scenarios as our training environment might not be able to load the entire dataset into memory at once."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "#Number of input data samples in a batch\n",
+ "BATCH_SIZE = 64\n",
+ "\n",
+ "#Shuffle buffer size for shuffling data\n",
+ "SHUFFLE_BUFFER_SIZE = 1000\n",
+ "\n",
+ "#Preloads PREFETCH_SIZE batches so that there is no idle time between batches\n",
+ "PREFETCH_SIZE = 4"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def prepare_dataset(filename):\n",
+ " \n",
+ " \"\"\"Load the samples used for training.\"\"\"\n",
+ " \n",
+ " data = np.load(filename)\n",
+ " data = np.asarray(data, dtype=np.float32) # {-1, 1}\n",
+ "\n",
+ " print('data shape = {}'.format(data.shape))\n",
+ "\n",
+ " dataset = tf.data.Dataset.from_tensor_slices(data)\n",
+ " dataset = dataset.shuffle(SHUFFLE_BUFFER_SIZE).repeat()\n",
+ " dataset = dataset.batch(BATCH_SIZE, drop_remainder=True)\n",
+ " dataset = dataset.prefetch(PREFETCH_SIZE)\n",
+ "\n",
+ " return dataset \n",
+ "\n",
+ "dataset = prepare_dataset('./dataset/train.npy')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Model architecture\n",
+ "In this section, we will walk through the architecture of the proposed GAN.\n",
+ "\n",
+ "The model consists of two networks, a generator and a critic. These two networks work in a tight loop as following:\n",
+ "\n",
+ "* Generator:\n",
+ " 1. The generator takes in a batch of single-track piano rolls (melody) as the input and generates a batch of multi-track piano rolls as the output by adding accompaniments to each of the input music tracks. \n",
+ " 2. The critic then takes these generated music tracks and predicts how far it deviates from the real data present in your training dataset.\n",
+ " 3. This feedback from the critic is used by the generator to update its weights.\n",
+ "* Critic: As the generator gets better at creating better music accompaniments using the feedback from the critic, the critic needs to be retrained as well.\n",
+ " 1. Train the critic with the music tracks just generated by the generator as fake inputs and an equivalent number of songs from the original dataset as the real input. \n",
+ "* Alternate between training these two networks until the model converges and produces realistic music, beginning with the critic on the first iteration.\n",
+ "\n",
+ "We use a special type of GAN called the **Wasserstein GAN with Gradient Penalty** (or **WGAN-GP**) to generate music. While the underlying architecture of a WGAN-GP is very similar to vanilla variants of GAN, WGAN-GPs help overcome some of the commonly seen defects in GANs such as the vanishing gradient problem and mode collapse (see appendix for more details).\n",
+ "\n",
+ "Note our \"critic\" network is more generally called a \"discriminator\" network in the more general context of vanilla GANs."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Generator"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The generator is adapted from the U-Net architecture (a popular CNN that is used extensively in the computer vision domain), consisting of an “encoder” that maps the single track music data (represented as piano roll images) to a relatively lower dimensional “latent space“ and a ”decoder“ that maps the latent space back to multi-track music data.\n",
+ "\n",
+ "Here are the inputs provided to the generator:\n",
+ "\n",
+ "**Single-track piano roll input**: A single melody track of size (32, 128, 1) => (TimeStep, NumPitches, NumTracks) is provided as the input to the generator. \n",
+ "\n",
+ "**Latent noise vector**: A latent noise vector z of dimension (2, 8, 512) is also passed in as input and this is responsible for ensuring that there is a distinctive flavor to each output generated by the generator, even when the same input is provided.\n",
+ "\n",
+ "Notice from the figure below that the encoding layers of the generator on the left side and decoder layer on on the right side are connected to create a U-shape, thereby giving the name U-Net to this architecture."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In this implementation, we build the generator following a simple four-level Unet architecture by combining `_conv2d`s and `_deconv2d`, where `_conv2d` compose the contracting path and `_deconv2d` forms the expansive path. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def _conv2d(layer_input, filters, f_size=4, bn=True):\n",
+ " \"\"\"Generator Basic Downsampling Block\"\"\"\n",
+ " d = tf.keras.layers.Conv2D(filters, kernel_size=f_size, strides=2,\n",
+ " padding='same')(layer_input)\n",
+ " d = tf.keras.layers.LeakyReLU(alpha=0.2)(d)\n",
+ " if bn:\n",
+ " d = tf.keras.layers.BatchNormalization(momentum=0.8)(d)\n",
+ " return d\n",
+ "\n",
+ "\n",
+ "def _deconv2d(layer_input, pre_input, filters, f_size=4, dropout_rate=0):\n",
+ " \"\"\"Generator Basic Upsampling Block\"\"\"\n",
+ " u = tf.keras.layers.UpSampling2D(size=2)(layer_input)\n",
+ " u = tf.keras.layers.Conv2D(filters, kernel_size=f_size, strides=1,\n",
+ " padding='same')(u)\n",
+ " u = tf.keras.layers.BatchNormalization(momentum=0.8)(u)\n",
+ " u = tf.keras.layers.ReLU()(u)\n",
+ "\n",
+ " if dropout_rate:\n",
+ " u = tf.keras.layers.Dropout(dropout_rate)(u)\n",
+ " \n",
+ " u = tf.keras.layers.Concatenate()([u, pre_input])\n",
+ " return u\n",
+ "\n",
+ " \n",
+ "def build_generator(condition_input_shape=(32, 128, 1), filters=64,\n",
+ " instruments=4, latent_shape=(2, 8, 512)):\n",
+ " \"\"\"Buld Generator\"\"\"\n",
+ " c_input = tf.keras.layers.Input(shape=condition_input_shape)\n",
+ " z_input = tf.keras.layers.Input(shape=latent_shape)\n",
+ "\n",
+ " d1 = _conv2d(c_input, filters, bn=False)\n",
+ " d2 = _conv2d(d1, filters * 2)\n",
+ " d3 = _conv2d(d2, filters * 4)\n",
+ " d4 = _conv2d(d3, filters * 8)\n",
+ "\n",
+ " d4 = tf.keras.layers.Concatenate(axis=-1)([d4, z_input])\n",
+ "\n",
+ " u4 = _deconv2d(d4, d3, filters * 4)\n",
+ " u5 = _deconv2d(u4, d2, filters * 2)\n",
+ " u6 = _deconv2d(u5, d1, filters)\n",
+ "\n",
+ " u7 = tf.keras.layers.UpSampling2D(size=2)(u6)\n",
+ " output = tf.keras.layers.Conv2D(instruments, kernel_size=4, strides=1,\n",
+ " padding='same', activation='tanh')(u7) # 32, 128, 4\n",
+ "\n",
+ " generator = tf.keras.models.Model([c_input, z_input], output, name='Generator')\n",
+ "\n",
+ " return generator"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Let us now dive into each layer of the generator to see the inputs/outputs at each layer."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Models\n",
+ "generator = build_generator()\n",
+ "generator.summary()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Critic (Discriminator)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The goal of the critic is to provide feedback to the generator about how realistic the generated piano rolls are, so that the generator can learn to produce more realistic data. The critic provides this feedback by outputting a scalar that represents how “real” or “fake” a piano roll is.\n",
+ "\n",
+ "Since the critic tries to classify data as “real” or “fake”, it is not very different from commonly used binary classifiers. We use a simple architecture for the critic, composed of four convolutional layers and a dense layer at the end."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "def _build_critic_layer(layer_input, filters, f_size=4):\n",
+ " \"\"\"\n",
+ " This layer decreases the spatial resolution by 2:\n",
+ "\n",
+ " input: [batch_size, in_channels, H, W]\n",
+ " output: [batch_size, out_channels, H/2, W/2]\n",
+ " \"\"\"\n",
+ " d = tf.keras.layers.Conv2D(filters, kernel_size=f_size, strides=2,\n",
+ " padding='same')(layer_input)\n",
+ " # Critic does not use batch-norm\n",
+ " d = tf.keras.layers.LeakyReLU(alpha=0.2)(d) \n",
+ " return d\n",
+ "\n",
+ "\n",
+ "def build_critic(pianoroll_shape=(32, 128, 4), filters=64):\n",
+ " \"\"\"WGAN critic.\"\"\"\n",
+ " \n",
+ " condition_input_shape = (32,128,1)\n",
+ " groundtruth_pianoroll = tf.keras.layers.Input(shape=pianoroll_shape)\n",
+ " condition_input = tf.keras.layers.Input(shape=condition_input_shape)\n",
+ " combined_imgs = tf.keras.layers.Concatenate(axis=-1)([groundtruth_pianoroll, condition_input])\n",
+ "\n",
+ "\n",
+ " \n",
+ " d1 = _build_critic_layer(combined_imgs, filters)\n",
+ " d2 = _build_critic_layer(d1, filters * 2)\n",
+ " d3 = _build_critic_layer(d2, filters * 4)\n",
+ " d4 = _build_critic_layer(d3, filters * 8)\n",
+ "\n",
+ " x = tf.keras.layers.Flatten()(d4)\n",
+ " logit = tf.keras.layers.Dense(1)(x)\n",
+ "\n",
+ " critic = tf.keras.models.Model([groundtruth_pianoroll,condition_input], logit,\n",
+ " name='Critic')\n",
+ " \n",
+ "\n",
+ " return critic"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Create the Discriminator\n",
+ "\n",
+ "critic = build_critic()\n",
+ "critic.summary() # View discriminator architecture."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Training\n",
+ "\n",
+ "We train our models by searching for model parameters which optimize an objective function. For our WGAN-GP, we have special loss functions that we minimize as we alternate between training our generator and critic networks:\n",
+ "\n",
+ "*Generator Loss:*\n",
+ "* We use the Wasserstein (Generator) loss function which is negative of the Critic Loss function. The generator is trained to bring the generated pianoroll as close to the real pianoroll as possible.\n",
+ " * $\\frac{1}{m} \\sum_{i=1}^{m} -D_w(G(z^{i}|c^{i})|c^{i})$\n",
+ "\n",
+ "*Critic Loss:*\n",
+ "\n",
+ "* We begin with the Wasserstein (Critic) loss function designed to maximize the distance between the real piano roll distribution and generated (fake) piano roll distribution.\n",
+ " * $\\frac{1}{m} \\sum_{i=1}^{m} [D_w(G(z^{i}|c^{i})|c^{i}) - D_w(x^{i}|c^{i})]$\n",
+ "\n",
+ "* We add a gradient penalty loss function term designed to control how the gradient of the critic with respect to its input behaves. This makes optimization of the generator easier. \n",
+ " * $\\frac{1}{m} \\sum_{i=1}^{m}(\\lVert \\nabla_{\\hat{x}^i}D_w(\\hat{x}^i|c^{i}) \\rVert_2 - 1)^2 $"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Define the different loss functions\n",
+ "\n",
+ "def generator_loss(critic_fake_output):\n",
+ " \"\"\" Wasserstein GAN loss\n",
+ " (Generator) -D(G(z|c))\n",
+ " \"\"\"\n",
+ " return -tf.reduce_mean(critic_fake_output)\n",
+ "\n",
+ "\n",
+ "def wasserstein_loss(critic_real_output, critic_fake_output):\n",
+ " \"\"\" Wasserstein GAN loss\n",
+ " (Critic) D(G(z|c)) - D(x|c)\n",
+ " \"\"\"\n",
+ " return tf.reduce_mean(critic_fake_output) - tf.reduce_mean(\n",
+ " critic_real_output)\n",
+ "\n",
+ "\n",
+ "def compute_gradient_penalty(critic, x, fake_x):\n",
+ " \n",
+ " c = tf.expand_dims(x[..., 0], -1)\n",
+ " batch_size = x.get_shape().as_list()[0]\n",
+ " eps_x = tf.random.uniform(\n",
+ " [batch_size] + [1] * (len(x.get_shape()) - 1)) # B, 1, 1, 1, 1\n",
+ " inter = eps_x * x + (1.0 - eps_x) * fake_x\n",
+ "\n",
+ " with tf.GradientTape() as g:\n",
+ " g.watch(inter)\n",
+ " disc_inter_output = critic((inter,c), training=True)\n",
+ " grads = g.gradient(disc_inter_output, inter)\n",
+ " slopes = tf.sqrt(1e-8 + tf.reduce_sum(\n",
+ " tf.square(grads),\n",
+ " reduction_indices=tf.range(1, grads.get_shape().ndims)))\n",
+ " gradient_penalty = tf.reduce_mean(tf.square(slopes - 1.0))\n",
+ " \n",
+ " return gradient_penalty\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "With our loss functions defined, we associate them with Tensorflow optimizers to define how our model will search for a good set of model parameters. We use the *Adam* algorithm, a commonly used general-purpose optimizer. We also set up checkpoints to save our progress as we train."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Setup Adam optimizers for both G and D\n",
+ "generator_optimizer = tf.keras.optimizers.Adam(1e-3, beta_1=0.5, beta_2=0.9)\n",
+ "critic_optimizer = tf.keras.optimizers.Adam(1e-3, beta_1=0.5, beta_2=0.9)\n",
+ "\n",
+ "# We define our checkpoint directory and where to save trained checkpoints\n",
+ "ckpt = tf.train.Checkpoint(generator=generator,\n",
+ " generator_optimizer=generator_optimizer,\n",
+ " critic=critic,\n",
+ " critic_optimizer=critic_optimizer)\n",
+ "ckpt_manager = tf.train.CheckpointManager(ckpt, check_dir, max_to_keep=5)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Now we define the `generator_train_step` and `critic_train_step` functions, each of which performs a single forward pass on a batch and returns the corresponding loss."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "@tf.function\n",
+ "def generator_train_step(x, condition_track_idx=0):\n",
+ "\n",
+ " ############################################\n",
+ " #(1) Update G network: maximize D(G(z|c))\n",
+ " ############################################\n",
+ "\n",
+ " # Extract condition track to make real batches pianoroll\n",
+ " c = tf.expand_dims(x[..., condition_track_idx], -1)\n",
+ "\n",
+ " # Generate batch of latent vectors\n",
+ " z = tf.random.truncated_normal([BATCH_SIZE, 2, 8, 512])\n",
+ "\n",
+ " with tf.GradientTape() as tape:\n",
+ " fake_x = generator((c, z), training=True)\n",
+ " fake_output = critic((fake_x,c), training=False)\n",
+ "\n",
+ " # Calculate Generator's loss based on this generated output\n",
+ " gen_loss = generator_loss(fake_output)\n",
+ "\n",
+ " # Calculate gradients for Generator\n",
+ " gradients_of_generator = tape.gradient(gen_loss,\n",
+ " generator.trainable_variables)\n",
+ " # Update Generator\n",
+ " generator_optimizer.apply_gradients(\n",
+ " zip(gradients_of_generator, generator.trainable_variables))\n",
+ "\n",
+ " return gen_loss\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "@tf.function\n",
+ "def critic_train_step(x, condition_track_idx=0):\n",
+ "\n",
+ " ############################################################################\n",
+ " #(2) Update D network: maximize (D(x|c)) + (1 - D(G(z|c))|c) + GradientPenality() \n",
+ " ############################################################################\n",
+ "\n",
+ " # Extract condition track to make real batches pianoroll\n",
+ " c = tf.expand_dims(x[..., condition_track_idx], -1)\n",
+ "\n",
+ " # Generate batch of latent vectors\n",
+ " z = tf.random.truncated_normal([BATCH_SIZE, 2, 8, 512])\n",
+ "\n",
+ " # Generated fake pianoroll\n",
+ " fake_x = generator((c, z), training=False)\n",
+ "\n",
+ "\n",
+ " # Update critic parameters\n",
+ " with tf.GradientTape() as tape:\n",
+ " real_output = critic((x,c), training=True)\n",
+ " fake_output = critic((fake_x,c), training=True)\n",
+ " critic_loss = wasserstein_loss(real_output, fake_output)\n",
+ "\n",
+ " # Caculate the gradients from the real and fake batches\n",
+ " grads_of_critic = tape.gradient(critic_loss,\n",
+ " critic.trainable_variables)\n",
+ "\n",
+ " with tf.GradientTape() as tape:\n",
+ " gp_loss = compute_gradient_penalty(critic, x, fake_x)\n",
+ " gp_loss *= 10.0\n",
+ "\n",
+ " # Calculate the gradients penalty from the real and fake batches\n",
+ " grads_gp = tape.gradient(gp_loss, critic.trainable_variables)\n",
+ " gradients_of_critic = [g + ggp for g, ggp in\n",
+ " zip(grads_of_critic, grads_gp)\n",
+ " if ggp is not None]\n",
+ "\n",
+ " # Update Critic\n",
+ " critic_optimizer.apply_gradients(\n",
+ " zip(gradients_of_critic, critic.trainable_variables))\n",
+ "\n",
+ " return critic_loss + gp_loss\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Before we begin training, let's define some training configuration parameters and prepare to monitor important quantities. Here we log the losses and metrics which we can use to determine when to stop training. Consider coming back here to tweak these parameters and explore how your model responds. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# We use load_melody_samples() to load 10 input data samples from our dataset into sample_x \n",
+ "# and 10 random noise latent vectors into sample_z\n",
+ "sample_x, sample_z = inference_utils.load_melody_samples(n_sample=10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Number of iterations to train for\n",
+ "iterations = 2000\n",
+ "\n",
+ "# Update critic n times per generator update \n",
+ "n_dis_updates_per_gen_update = 5\n",
+ "\n",
+ "# Determine input track in sample_x that we condition on\n",
+ "condition_track_idx = 0 \n",
+ "sample_c = tf.expand_dims(sample_x[..., condition_track_idx], -1)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Let us now train our model!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Clear out any old metrics we've collected\n",
+ "metrics_utils.metrics_manager.initialize()\n",
+ "\n",
+ "# Keep a running list of various quantities:\n",
+ "c_losses = []\n",
+ "g_losses = []\n",
+ "\n",
+ "# Data iterator to iterate over our dataset\n",
+ "it = iter(dataset)\n",
+ "\n",
+ "for iteration in range(iterations):\n",
+ "\n",
+ " # Train critic\n",
+ " for _ in range(n_dis_updates_per_gen_update):\n",
+ " c_loss = critic_train_step(next(it))\n",
+ "\n",
+ " # Train generator\n",
+ " g_loss = generator_train_step(next(it))\n",
+ "\n",
+ " # Save Losses for plotting later\n",
+ " c_losses.append(c_loss)\n",
+ " g_losses.append(g_loss)\n",
+ "\n",
+ " display.clear_output(wait=True)\n",
+ " fig = plt.figure(figsize=(15, 5))\n",
+ " line1, = plt.plot(range(iteration+1), c_losses, 'r')\n",
+ " line2, = plt.plot(range(iteration+1), g_losses, 'k')\n",
+ " plt.xlabel('Iterations')\n",
+ " plt.ylabel('Losses')\n",
+ " plt.legend((line1, line2), ('C-loss', 'G-loss'))\n",
+ " display.display(fig)\n",
+ " plt.close(fig)\n",
+ " \n",
+ " # Output training stats\n",
+ " print('Iteration {}, c_loss={:.2f}, g_loss={:.2f}'.format(iteration, c_loss, g_loss))\n",
+ " \n",
+ " # Save checkpoints, music metrics, generated output\n",
+ " if iteration < 100 or iteration % 50 == 0 :\n",
+ " # Check how the generator is doing by saving G's samples on fixed_noise\n",
+ " fake_sample_x = generator((sample_c, sample_z), training=False)\n",
+ " metrics_utils.metrics_manager.append_metrics_for_iteration(fake_sample_x.numpy(), iteration)\n",
+ "\n",
+ " if iteration % 50 == 0:\n",
+ " # Save the checkpoint to disk.\n",
+ " ckpt_manager.save(checkpoint_number=iteration) \n",
+ " \n",
+ " fake_sample_x = fake_sample_x.numpy()\n",
+ " \n",
+ " # plot the pianoroll\n",
+ " display_utils.plot_pianoroll(iteration, sample_x[:4], fake_sample_x[:4], save_dir=train_dir)\n",
+ "\n",
+ " # generate the midi\n",
+ " destination_path = path_utils.generated_midi_path_for_iteration(iteration, saveto_dir=sample_dir)\n",
+ " midi_utils.save_pianoroll_as_midi(fake_sample_x[:4], destination_path=destination_path)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### We have started training!\n",
+ "\n",
+ "When using the Wasserstein loss function, we should train the critic to converge to ensure that the gradients for the generator update are accurate. This is in contrast to a standard GAN, where it is important not to let the critic get too strong, to avoid vanishing gradients.\n",
+ "\n",
+ "Therefore, using the Wasserstein loss removes one of the key difficulties of training GANs—how to balance the training of the discriminator and generator. With WGANs, we can simply train the critic several times between generator updates, to ensure it is close to convergence. A typical ratio used is five critic updates to one generator update.\n",
+ "\n",
+ "### \"Babysitting\" the learning process\n",
+ "\n",
+ "Given that training these models can be an investment in time and resources, we must to continuously monitor training in order to catch and address anomalies if/when they occur. Here are some things to look out for:\n",
+ "\n",
+ "**What should the losses look like?**\n",
+ "\n",
+ "The adversarial learning process is highly dynamic and high-frequency oscillations are quite common. However if either loss (critic or generator) skyrockets to huge values, plunges to 0, or get stuck on a single value, there is likely an issue somewhere.\n",
+ "\n",
+ "**Is my model learning?**\n",
+ "- Monitor the critic loss and other music quality metrics (if applicable). Are they following the expected trajectories?\n",
+ "- Monitor the generated samples (piano rolls). Are they improving over time? Do you see evidence of mode collapse? Have you tried listening to your samples?\n",
+ "\n",
+ "**How do I know when to stop?**\n",
+ "- If the samples meet your expectations\n",
+ "- Critic loss no longer improving\n",
+ "- The expected value of the musical quality metrics converge to the corresponding expected value of the same metric on the training data"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### How to measure sample quality during training \n",
+ "\n",
+ "Typically, when training any sort of neural networks, it is standard practice to monitor the value of the loss function throughout the duration of the training. The critic loss in WGANs has been found to correlate well with sample quality.\n",
+ "\n",
+ "While standard mechanisms exist for evaluating the accuracy of more traditional models like classifiers or regressors, evaluating generative models is an active area of research. Within the domain of music generation, this hard problem is even less well-understood.\n",
+ "\n",
+ "To address this, we take high-level measurements of our data and show how well our model produces music that aligns with those measurements. If our model produces music which is close to the mean value of these measurements for our training dataset, our music should match on general “shape”.\n",
+ "\n",
+ "We’ll look at three such measurements:\n",
+ "- **Empty bar rate:** The ratio of empty bars to total number of bars.\n",
+ "- **Pitch histogram distance:** A metric that captures the distribution and position of pitches.\n",
+ "- **In Scale Ratio:** Ratio of the number of notes that are in C major key, which is a common key found in music, to the total number of notes. \n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Evaluate results\n",
+ "\n",
+ "Now that we have finished training, let's find out how we did. We will analyze our model in several ways:\n",
+ "1. Examine how the generator and critic losses changed while training\n",
+ "2. Understand how certain musical metrics changed while training\n",
+ "3. Visualize generated piano roll output for a fixed input at every iteration and create a video\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Let us first restore our last saved checkpoint. If you did not complete training but still want to continue with a pre-trained version, set `TRAIN = False`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ckpt = tf.train.Checkpoint(generator=generator)\n",
+ "ckpt_manager = tf.train.CheckpointManager(ckpt, check_dir, max_to_keep=5)\n",
+ "\n",
+ "ckpt.restore(ckpt_manager.latest_checkpoint).expect_partial()\n",
+ "print('Latest checkpoint {} restored.'.format(ckpt_manager.latest_checkpoint))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Plot losses"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "display_utils.plot_loss_logs(g_losses, c_losses, figsize=(15, 5), smoothing=0.01)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Observe how the critic loss (C_loss in the graph) decays to zero as we train. In WGAN-GPs, the critic loss decreases (almost) monotonically as you train."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Plot metrics"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "metrics_utils.metrics_manager.set_reference_metrics(training_data)\n",
+ "metrics_utils.metrics_manager.plot_metrics()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Each row here corresponds to a different music quality metric and each column denotes an instrument track. \n",
+ "\n",
+ "Observe how the expected value of the different metrics (blue scatter) approach the corresponding training set expected values (red) as the number of iterations increase. You might expect to see diminishing returns as the model converges.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Generated samples during training\n",
+ "\n",
+ "The function below helps you probe intermediate samples generated in the training process. Remember that the conditioned input here is sampled from our training data. Let's start by listening to and observing a sample at iteration 0 and then iteration 100. Notice the difference!\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Enter an iteration number (can be divided by 50) and listen to the midi at that iteration\n",
+ "iteration = 50\n",
+ "midi_file = os.path.join(sample_dir, 'iteration-{}.mid'.format(iteration))\n",
+ "display_utils.playmidi(midi_file) "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Enter an iteration number (can be divided by 50) and look at the generated pianorolls at that iteration\n",
+ "iteration = 50\n",
+ "pianoroll_png = os.path.join(train_dir, 'sample_iteration_%05d.png' % iteration)\n",
+ "display.Image(filename=pianoroll_png)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Let's see how the generated piano rolls change with the number of iterations."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from IPython.display import Video\n",
+ "\n",
+ "\n",
+ "display_utils.make_training_video(train_dir)\n",
+ "video_path = \"movie.mp4\"\n",
+ "Video(video_path)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Inference "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Generating accompaniment for custom input\n",
+ "\n",
+ "Congratulations! You have trained your very own WGAN-GP to generate music. Let us see how our generator performs on a custom input.\n",
+ "\n",
+ "The function below generates a new song based on \"Twinkle Twinkle Little Star\"."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "latest_midi = inference_utils.generate_midi(generator, eval_dir, input_midi_file='./input_twinkle_twinkle.mid')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "display_utils.playmidi(latest_midi)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We can also take a look at the generated piano rolls for a certain sample, to see how diverse they are!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "inference_utils.show_generated_pianorolls(generator, eval_dir, input_midi_file='./input_twinkle_twinkle.mid')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# What's next?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Using your own data (Optional)\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "To create your own dataset you can extract the piano roll from MIDI data. An example of creating a piano roll from a MIDI file is given below"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "from pypianoroll import Multitrack\n",
+ "\n",
+ "midi_data = Multitrack('./input_twinkle_twinkle.mid')\n",
+ "tracks = [track.pianoroll for track in midi_data.tracks]\n",
+ "sample = np.stack(tracks, axis=-1)\n",
+ "\n",
+ "print(sample.shape)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Appendix"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Open source implementations\n",
+ "For more open-source implementations of generative models for music, check out:\n",
+ "\n",
+ "- [MuseGAN](https://github.com/salu133445/musegan): Official TensorFlow Implementation that uses GANs to generate multi track polyphonic music\n",
+ "- [GANSynth](https://github.com/tensorflow/magenta/tree/master/magenta/models/gansynth): GANSynth uses a Progressive GAN architecture to incrementally upsample with convolution from a single vector to the full audio spectrogram\n",
+ "- [Music Transformer](https://github.com/tensorflow/magenta/tree/master/magenta/models/score2perf): Uses transformers to generate music!\n",
+ "\n",
+ "GANs have also achieved state of the generative modeling in several other domains including cross domain image tranfer, celebrity face generation, super resolution text to image and image inpainting.\n",
+ "\n",
+ "- [Keras-GAN](https://github.com/eriklindernoren/Keras-GAN): Library of reference implementations in Keras for image generation(good for educational purposes).\n",
+ "\n",
+ "There's an ocean of literatures out there that use GANs for modeling distributions across fields! If you are interested, [Gan Zoo](https://github.com/hindupuravinash/the-gan-zoo) is a good place to start."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### References\n",
+ "\n",
+ "1. [Dong, H.W., Hsiao, W.Y., Yang, L.C. and Yang, Y.H., 2018, April. MuseGAN: Multi-track sequential generative adversarial networks for symbolic music generation and accompaniment. In Thirty-Second AAAI Conference on Artificial Intelligence.](https://arxiv.org/abs/1709.06298)\n",
+ "2. [Ishaan, G., Faruk, A., Martin, A., Vincent, D. and Aaron, C., 2017. Improved training of wasserstein gans. In Advances in Neural Information Processing Systems.](https://arxiv.org/abs/1704.00028)\n",
+ "3. [Arjovsky, M., Chintala, S. and Bottou, L., 2017. Wasserstein gan. arXiv preprint arXiv:1701.07875.](https://arxiv.org/abs/1701.07875)\n",
+ "4. [Foster, D., 2019. Generative Deep Learning: Teaching Machines to Paint, Write, Compose, and Play. O'Reilly Media.](https://www.amazon.com/Generative-Deep-Learning-Teaching-Machines/dp/1492041947)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### More on Wassertein GAN with Gradient Penalty (optional)\n",
+ "\n",
+ "While GANs are a major breakthrough for generative modeling, plain GANs are also notoriously difficult to train. Some common problems encountered are:\n",
+ "\n",
+ "* **Oscillating loss:** The loss of the discriminator and generator can start to oscillate without exhibiting any long term stability.\n",
+ "* **Mode collapse:** The generator may get stuck on a small set of samples that always fool the discriminator. This reduces the capability of the network to produce novel samples.\n",
+ "* **Uninformative loss:** The lack of correlation between the generator loss and quality of generated output makes plain GAN training difficult to interpret.\n",
+ "\n",
+ "\n",
+ "The [Wasserstein GAN](#references) was a major advancement in GANs and helped mitigate to some of these issues. Some of its features are:\n",
+ "\n",
+ "1. It significantly improves the interpretability of loss functions and provides clearer stopping criteria\n",
+ "2. WGANs generally produce results of higher quality (demonstrated within the image generation domain)\n",
+ "\n",
+ "**Mathematics of Wasserstein GAN with Gradient Penalty**\n",
+ "\n",
+ "The [Wasserstein distance](https://en.wikipedia.org/wiki/Wasserstein_metric) between the true distribution $P_r$ and generated piano roll distribution $P_g$ is defined as follows:\n",
+ "\n",
+ "$$\\mathbb{W}(P_{r},P_{g})=\\sup_{\\lVert{f} \\rVert_{L} \\le 1} \\mathbb{E}_{x \\sim \\mathbb{P}_r}(f(x)) - \\mathbb{E}_{x \\sim \\mathbb{P}_g}(f(x)) $$\n",
+ "\n",
+ "In this equation we are trying to minimize the distance between the expectation of the real distribution and the expectation of the generation distribution. $f$ is subject to a technical constraint in that it must be [1-Lipschitz](https://en.wikipedia.org/wiki/Lipschitz_continuity).\n",
+ "\n",
+ "To enforce the 1-Lipschitz condition that basically constraints the gradients from varying too rapidly we use the gradient penalty.\n",
+ "\n",
+ "**Gradient penalty**: We want to penalize the gradients of the critic. We implicitly define $P_{\\hat{x}}$ by sampling uniformly along straight lines between pairs of points sampled from the data distribution $P_r$ and the generator distribution $P_g$. This was originally motivated by the fact that the optimal critic contains straight lines with gradient norm 1 connecting coupled points from $P_r$ and $P_g$. We use a penalty coefficient $\\lambda$= 10 as was recommended in the original paper. \n",
+ "\n",
+ "The loss with gradient penalty is:\n",
+ "\n",
+ "$$\\mathbb{L}(P_{r},P_{g},P_{\\hat{x}} )= \\mathbb{W}(P_{r},P_{g}) + \\lambda \\mathbb{E}_{\\hat{x} \\sim \\mathbb{P}_\\hat{x}}[(\\lVert \\nabla_{\\hat{x}}D(\\hat{x}) \\rVert_2 - 1)^2]$$\n",
+ "|\n",
+ "This loss can be parametrized in terms of $w$ and $\\theta$. We then use neural networks to learn the functions $f_w$ (discriminator) and $g_\\theta$ (generator).\n",
+ "$$\\mathbb{W}(P_{r},P_{\\theta})=\\max_{w \\in \\mathbb{W}} \\mathbb{E}_{x \\sim \\mathbb{P}_r}(D_w(x)) - \\mathbb{E}_{z \\sim p(z)}(D_w(G_{\\theta}(z)) $$\n",
+ "$$\\mathbb{L}(P_{r},P_{\\theta},P_{\\hat{x}})=\\max_{w \\in \\mathbb{W}} \\mathbb{E}_{x \\sim \\mathbb{P}_r}(D_w(x)) - \\mathbb{E}_{z \\sim p(z)}(D_w(G_{\\theta}(z)) + \\lambda \\mathbb{E}_{\\hat{x} \\sim \\mathbb{P}_\\hat{x}}[(\\lVert \\nabla_{\\hat{x}}D_w(\\hat{x}) \\rVert_2 - 1)^2]$$\n",
+ "\n",
+ "where $$ \\hat{x} = \\epsilon x + (1- \\epsilon) G(z) $$ and $$\\epsilon \\sim Unif(0,1)$$\n",
+ "\n",
+ "The basic procedure to train is as following: \n",
+ "1. We draw real_x from the real distribution $P_r$ and fake_x from the generated distribution $G_{\\theta}(z)$ where $z \\sim p(z)$\n",
+ "2. The latent vectors are sampled from z and then tranformed using the generator $G_{\\theta}$ to get the fake samples fake_x. They are evaluated using the critic function $D_w$\n",
+ "3. We are trying to minimize the Wasserstein distance between the two distributions\n",
+ "\n",
+ "Both the generator and critic are conditioned on the input pianoroll melody."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "conda_python3",
+ "language": "python",
+ "name": "conda_python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.9"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/Lab 2/Lifecycle_configurations.sh b/Lab 2/Lifecycle_configurations.sh
new file mode 100644
index 0000000..36e28ca
--- /dev/null
+++ b/Lab 2/Lifecycle_configurations.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+set -e
+
+# OVERVIEW
+# This script installs all necessary software for running the DeepComposer GAN notebook.
+
+sudo -u ec2-user -i <<'EOF'
+ENVIRONMENT=python3
+source /home/ec2-user/anaconda3/bin/activate "$ENVIRONMENT"
+
+conda update --all --y
+pip install tensorflow==1.14.0
+pip install numpy==1.16.4
+pip install pretty_midi
+pip install pypianoroll
+pip install music21
+pip install seaborn
+pip install --ignore-installed moviepy
+
+source /home/ec2-user/anaconda3/bin/deactivate
+EOF
\ No newline at end of file
diff --git a/Lab 2/README.md b/Lab 2/README.md
index 405f31e..e452fff 100644
--- a/Lab 2/README.md
+++ b/Lab 2/README.md
@@ -8,26 +8,40 @@ Navigate to Amazon SageMaker using the link: https://console.aws.amazon.com/sage
Click **Notebook instances** from the left navigation bar
-
+Select **Create notebook instance**
+
+
+
+Within the notebook instance creation form, select "c5.4xlarge" for **Notebook instance type**
+
+
+
+Set the following for **Permissions and encryption**:
+* IAM role: Use an existing role or create a new role
+* Root access: Enable
+* Encryption key: No Custom Encryption
+
+
+
+Set the following for **Git repositories**:
+* Repository: Clone a public Git repository to this notebook instance only
+* Git repository URL: https://github.com/aws-samples/aws-deepcomposer-samples
+
+
Click **Open Jupyter**
-
+
-Click **DeepComposerWorkshop** folder
+Click **Lab 2** folder, then click **GAN.ipynb**

-Click **GAN.ipynb**
-
-
-*If you come across the above error, choose the drop down and select **conda_python3** as the kernel*
+*You will likely be prompted to select kernel. Choose the drop down and select **conda_python3** as the kernel*

-Select **conda_python3** as the kernel and click **set kernel**
-
This notebook contains instructions and code to create a custom GAN model from scratch. Scroll through the notebook content.

diff --git a/Lab 2/dataset/JSPChorales.h5 b/Lab 2/dataset/JSPChorales.h5
new file mode 100644
index 0000000..ac9b98e
Binary files /dev/null and b/Lab 2/dataset/JSPChorales.h5 differ
diff --git a/Lab 2/dataset/eval.npy b/Lab 2/dataset/eval.npy
new file mode 100644
index 0000000..83adabc
Binary files /dev/null and b/Lab 2/dataset/eval.npy differ
diff --git a/Lab 2/dataset/train.npy b/Lab 2/dataset/train.npy
new file mode 100644
index 0000000..83adabc
Binary files /dev/null and b/Lab 2/dataset/train.npy differ
diff --git a/Lab 2/images/create_notebook.png b/Lab 2/images/create_notebook.png
new file mode 100644
index 0000000..37a62b9
Binary files /dev/null and b/Lab 2/images/create_notebook.png differ
diff --git a/Lab 2/images/ddis.pdf b/Lab 2/images/ddis.pdf
new file mode 100644
index 0000000..c645e85
Binary files /dev/null and b/Lab 2/images/ddis.pdf differ
diff --git a/Lab 2/images/ddis.png b/Lab 2/images/ddis.png
new file mode 100644
index 0000000..3325b59
Binary files /dev/null and b/Lab 2/images/ddis.png differ
diff --git a/Lab 2/images/dgan.pdf b/Lab 2/images/dgan.pdf
new file mode 100644
index 0000000..f0baec5
Binary files /dev/null and b/Lab 2/images/dgan.pdf differ
diff --git a/Lab 2/images/dgan.png b/Lab 2/images/dgan.png
new file mode 100644
index 0000000..9148306
Binary files /dev/null and b/Lab 2/images/dgan.png differ
diff --git a/Lab 2/images/dgen.pdf b/Lab 2/images/dgen.pdf
new file mode 100644
index 0000000..eb147d5
Binary files /dev/null and b/Lab 2/images/dgen.pdf differ
diff --git a/Lab 2/images/dgen.png b/Lab 2/images/dgen.png
new file mode 100644
index 0000000..f3ff528
Binary files /dev/null and b/Lab 2/images/dgen.png differ
diff --git a/Lab 2/images/notebook_git_settings.png b/Lab 2/images/notebook_git_settings.png
new file mode 100644
index 0000000..760a9e7
Binary files /dev/null and b/Lab 2/images/notebook_git_settings.png differ
diff --git a/Lab 2/images/notebook_instance_settings.png b/Lab 2/images/notebook_instance_settings.png
new file mode 100644
index 0000000..92d3397
Binary files /dev/null and b/Lab 2/images/notebook_instance_settings.png differ
diff --git a/Lab 2/images/open_jupyter.png b/Lab 2/images/open_jupyter.png
new file mode 100644
index 0000000..8bc607c
Binary files /dev/null and b/Lab 2/images/open_jupyter.png differ
diff --git a/Lab 2/images/permissions_and_encryption.png b/Lab 2/images/permissions_and_encryption.png
new file mode 100644
index 0000000..a8828fe
Binary files /dev/null and b/Lab 2/images/permissions_and_encryption.png differ
diff --git a/Lab 2/images/pianoroll2.png b/Lab 2/images/pianoroll2.png
new file mode 100644
index 0000000..996ffa2
Binary files /dev/null and b/Lab 2/images/pianoroll2.png differ
diff --git a/Lab 2/images/pianoroll_timesteps.png b/Lab 2/images/pianoroll_timesteps.png
new file mode 100644
index 0000000..6e98bcf
Binary files /dev/null and b/Lab 2/images/pianoroll_timesteps.png differ
diff --git a/Lab 2/input_twinkle_twinkle.mid b/Lab 2/input_twinkle_twinkle.mid
new file mode 100644
index 0000000..8dbde11
Binary files /dev/null and b/Lab 2/input_twinkle_twinkle.mid differ
diff --git a/Lab 2/original_midi/MIDI-0.mid b/Lab 2/original_midi/MIDI-0.mid
new file mode 100644
index 0000000..1f09dcc
Binary files /dev/null and b/Lab 2/original_midi/MIDI-0.mid differ
diff --git a/Lab 2/original_midi/MIDI-1.mid b/Lab 2/original_midi/MIDI-1.mid
new file mode 100644
index 0000000..07af303
Binary files /dev/null and b/Lab 2/original_midi/MIDI-1.mid differ
diff --git a/Lab 2/original_midi/MIDI-10.mid b/Lab 2/original_midi/MIDI-10.mid
new file mode 100644
index 0000000..615a1f6
Binary files /dev/null and b/Lab 2/original_midi/MIDI-10.mid differ
diff --git a/Lab 2/original_midi/MIDI-100.mid b/Lab 2/original_midi/MIDI-100.mid
new file mode 100644
index 0000000..59c38de
Binary files /dev/null and b/Lab 2/original_midi/MIDI-100.mid differ
diff --git a/Lab 2/original_midi/MIDI-101.mid b/Lab 2/original_midi/MIDI-101.mid
new file mode 100644
index 0000000..44ca371
Binary files /dev/null and b/Lab 2/original_midi/MIDI-101.mid differ
diff --git a/Lab 2/original_midi/MIDI-102.mid b/Lab 2/original_midi/MIDI-102.mid
new file mode 100644
index 0000000..35ceb8b
Binary files /dev/null and b/Lab 2/original_midi/MIDI-102.mid differ
diff --git a/Lab 2/original_midi/MIDI-103.mid b/Lab 2/original_midi/MIDI-103.mid
new file mode 100644
index 0000000..feb72c0
Binary files /dev/null and b/Lab 2/original_midi/MIDI-103.mid differ
diff --git a/Lab 2/original_midi/MIDI-104.mid b/Lab 2/original_midi/MIDI-104.mid
new file mode 100644
index 0000000..1b2be37
Binary files /dev/null and b/Lab 2/original_midi/MIDI-104.mid differ
diff --git a/Lab 2/original_midi/MIDI-105.mid b/Lab 2/original_midi/MIDI-105.mid
new file mode 100644
index 0000000..c18fe28
Binary files /dev/null and b/Lab 2/original_midi/MIDI-105.mid differ
diff --git a/Lab 2/original_midi/MIDI-106.mid b/Lab 2/original_midi/MIDI-106.mid
new file mode 100644
index 0000000..cc942ce
Binary files /dev/null and b/Lab 2/original_midi/MIDI-106.mid differ
diff --git a/Lab 2/original_midi/MIDI-107.mid b/Lab 2/original_midi/MIDI-107.mid
new file mode 100644
index 0000000..186a234
Binary files /dev/null and b/Lab 2/original_midi/MIDI-107.mid differ
diff --git a/Lab 2/original_midi/MIDI-108.mid b/Lab 2/original_midi/MIDI-108.mid
new file mode 100644
index 0000000..d3e1b8a
Binary files /dev/null and b/Lab 2/original_midi/MIDI-108.mid differ
diff --git a/Lab 2/original_midi/MIDI-109.mid b/Lab 2/original_midi/MIDI-109.mid
new file mode 100644
index 0000000..6d1a9be
Binary files /dev/null and b/Lab 2/original_midi/MIDI-109.mid differ
diff --git a/Lab 2/original_midi/MIDI-11.mid b/Lab 2/original_midi/MIDI-11.mid
new file mode 100644
index 0000000..1e8e1c0
Binary files /dev/null and b/Lab 2/original_midi/MIDI-11.mid differ
diff --git a/Lab 2/original_midi/MIDI-110.mid b/Lab 2/original_midi/MIDI-110.mid
new file mode 100644
index 0000000..c2be411
Binary files /dev/null and b/Lab 2/original_midi/MIDI-110.mid differ
diff --git a/Lab 2/original_midi/MIDI-111.mid b/Lab 2/original_midi/MIDI-111.mid
new file mode 100644
index 0000000..08cabc6
Binary files /dev/null and b/Lab 2/original_midi/MIDI-111.mid differ
diff --git a/Lab 2/original_midi/MIDI-112.mid b/Lab 2/original_midi/MIDI-112.mid
new file mode 100644
index 0000000..1003b7e
Binary files /dev/null and b/Lab 2/original_midi/MIDI-112.mid differ
diff --git a/Lab 2/original_midi/MIDI-113.mid b/Lab 2/original_midi/MIDI-113.mid
new file mode 100644
index 0000000..4a9e919
Binary files /dev/null and b/Lab 2/original_midi/MIDI-113.mid differ
diff --git a/Lab 2/original_midi/MIDI-114.mid b/Lab 2/original_midi/MIDI-114.mid
new file mode 100644
index 0000000..6e8c89b
Binary files /dev/null and b/Lab 2/original_midi/MIDI-114.mid differ
diff --git a/Lab 2/original_midi/MIDI-115.mid b/Lab 2/original_midi/MIDI-115.mid
new file mode 100644
index 0000000..979e9d8
Binary files /dev/null and b/Lab 2/original_midi/MIDI-115.mid differ
diff --git a/Lab 2/original_midi/MIDI-116.mid b/Lab 2/original_midi/MIDI-116.mid
new file mode 100644
index 0000000..deaab3c
Binary files /dev/null and b/Lab 2/original_midi/MIDI-116.mid differ
diff --git a/Lab 2/original_midi/MIDI-117.mid b/Lab 2/original_midi/MIDI-117.mid
new file mode 100644
index 0000000..2993367
Binary files /dev/null and b/Lab 2/original_midi/MIDI-117.mid differ
diff --git a/Lab 2/original_midi/MIDI-118.mid b/Lab 2/original_midi/MIDI-118.mid
new file mode 100644
index 0000000..ca47a45
Binary files /dev/null and b/Lab 2/original_midi/MIDI-118.mid differ
diff --git a/Lab 2/original_midi/MIDI-119.mid b/Lab 2/original_midi/MIDI-119.mid
new file mode 100644
index 0000000..f73febf
Binary files /dev/null and b/Lab 2/original_midi/MIDI-119.mid differ
diff --git a/Lab 2/original_midi/MIDI-12.mid b/Lab 2/original_midi/MIDI-12.mid
new file mode 100644
index 0000000..b703d1a
Binary files /dev/null and b/Lab 2/original_midi/MIDI-12.mid differ
diff --git a/Lab 2/original_midi/MIDI-120.mid b/Lab 2/original_midi/MIDI-120.mid
new file mode 100644
index 0000000..05b51f0
Binary files /dev/null and b/Lab 2/original_midi/MIDI-120.mid differ
diff --git a/Lab 2/original_midi/MIDI-121.mid b/Lab 2/original_midi/MIDI-121.mid
new file mode 100644
index 0000000..926f198
Binary files /dev/null and b/Lab 2/original_midi/MIDI-121.mid differ
diff --git a/Lab 2/original_midi/MIDI-122.mid b/Lab 2/original_midi/MIDI-122.mid
new file mode 100644
index 0000000..b73f5ab
Binary files /dev/null and b/Lab 2/original_midi/MIDI-122.mid differ
diff --git a/Lab 2/original_midi/MIDI-123.mid b/Lab 2/original_midi/MIDI-123.mid
new file mode 100644
index 0000000..2339c2e
Binary files /dev/null and b/Lab 2/original_midi/MIDI-123.mid differ
diff --git a/Lab 2/original_midi/MIDI-124.mid b/Lab 2/original_midi/MIDI-124.mid
new file mode 100644
index 0000000..076725d
Binary files /dev/null and b/Lab 2/original_midi/MIDI-124.mid differ
diff --git a/Lab 2/original_midi/MIDI-125.mid b/Lab 2/original_midi/MIDI-125.mid
new file mode 100644
index 0000000..14fbf98
Binary files /dev/null and b/Lab 2/original_midi/MIDI-125.mid differ
diff --git a/Lab 2/original_midi/MIDI-126.mid b/Lab 2/original_midi/MIDI-126.mid
new file mode 100644
index 0000000..ef31a2b
Binary files /dev/null and b/Lab 2/original_midi/MIDI-126.mid differ
diff --git a/Lab 2/original_midi/MIDI-127.mid b/Lab 2/original_midi/MIDI-127.mid
new file mode 100644
index 0000000..ddd4cae
Binary files /dev/null and b/Lab 2/original_midi/MIDI-127.mid differ
diff --git a/Lab 2/original_midi/MIDI-128.mid b/Lab 2/original_midi/MIDI-128.mid
new file mode 100644
index 0000000..1f67f9d
Binary files /dev/null and b/Lab 2/original_midi/MIDI-128.mid differ
diff --git a/Lab 2/original_midi/MIDI-129.mid b/Lab 2/original_midi/MIDI-129.mid
new file mode 100644
index 0000000..e9a50ab
Binary files /dev/null and b/Lab 2/original_midi/MIDI-129.mid differ
diff --git a/Lab 2/original_midi/MIDI-13.mid b/Lab 2/original_midi/MIDI-13.mid
new file mode 100644
index 0000000..b094863
Binary files /dev/null and b/Lab 2/original_midi/MIDI-13.mid differ
diff --git a/Lab 2/original_midi/MIDI-130.mid b/Lab 2/original_midi/MIDI-130.mid
new file mode 100644
index 0000000..aa146b1
Binary files /dev/null and b/Lab 2/original_midi/MIDI-130.mid differ
diff --git a/Lab 2/original_midi/MIDI-131.mid b/Lab 2/original_midi/MIDI-131.mid
new file mode 100644
index 0000000..912aa6c
Binary files /dev/null and b/Lab 2/original_midi/MIDI-131.mid differ
diff --git a/Lab 2/original_midi/MIDI-132.mid b/Lab 2/original_midi/MIDI-132.mid
new file mode 100644
index 0000000..23d6cc1
Binary files /dev/null and b/Lab 2/original_midi/MIDI-132.mid differ
diff --git a/Lab 2/original_midi/MIDI-133.mid b/Lab 2/original_midi/MIDI-133.mid
new file mode 100644
index 0000000..12290dc
Binary files /dev/null and b/Lab 2/original_midi/MIDI-133.mid differ
diff --git a/Lab 2/original_midi/MIDI-134.mid b/Lab 2/original_midi/MIDI-134.mid
new file mode 100644
index 0000000..0487cfa
Binary files /dev/null and b/Lab 2/original_midi/MIDI-134.mid differ
diff --git a/Lab 2/original_midi/MIDI-135.mid b/Lab 2/original_midi/MIDI-135.mid
new file mode 100644
index 0000000..9ae49c4
Binary files /dev/null and b/Lab 2/original_midi/MIDI-135.mid differ
diff --git a/Lab 2/original_midi/MIDI-136.mid b/Lab 2/original_midi/MIDI-136.mid
new file mode 100644
index 0000000..b5f0d2a
Binary files /dev/null and b/Lab 2/original_midi/MIDI-136.mid differ
diff --git a/Lab 2/original_midi/MIDI-137.mid b/Lab 2/original_midi/MIDI-137.mid
new file mode 100644
index 0000000..c0c7b9f
Binary files /dev/null and b/Lab 2/original_midi/MIDI-137.mid differ
diff --git a/Lab 2/original_midi/MIDI-138.mid b/Lab 2/original_midi/MIDI-138.mid
new file mode 100644
index 0000000..68dfb8d
Binary files /dev/null and b/Lab 2/original_midi/MIDI-138.mid differ
diff --git a/Lab 2/original_midi/MIDI-139.mid b/Lab 2/original_midi/MIDI-139.mid
new file mode 100644
index 0000000..6409097
Binary files /dev/null and b/Lab 2/original_midi/MIDI-139.mid differ
diff --git a/Lab 2/original_midi/MIDI-14.mid b/Lab 2/original_midi/MIDI-14.mid
new file mode 100644
index 0000000..c5f99fe
Binary files /dev/null and b/Lab 2/original_midi/MIDI-14.mid differ
diff --git a/Lab 2/original_midi/MIDI-140.mid b/Lab 2/original_midi/MIDI-140.mid
new file mode 100644
index 0000000..be5ccf5
Binary files /dev/null and b/Lab 2/original_midi/MIDI-140.mid differ
diff --git a/Lab 2/original_midi/MIDI-141.mid b/Lab 2/original_midi/MIDI-141.mid
new file mode 100644
index 0000000..835285e
Binary files /dev/null and b/Lab 2/original_midi/MIDI-141.mid differ
diff --git a/Lab 2/original_midi/MIDI-142.mid b/Lab 2/original_midi/MIDI-142.mid
new file mode 100644
index 0000000..b61c7cd
Binary files /dev/null and b/Lab 2/original_midi/MIDI-142.mid differ
diff --git a/Lab 2/original_midi/MIDI-143.mid b/Lab 2/original_midi/MIDI-143.mid
new file mode 100644
index 0000000..7b956ff
Binary files /dev/null and b/Lab 2/original_midi/MIDI-143.mid differ
diff --git a/Lab 2/original_midi/MIDI-144.mid b/Lab 2/original_midi/MIDI-144.mid
new file mode 100644
index 0000000..9461c81
Binary files /dev/null and b/Lab 2/original_midi/MIDI-144.mid differ
diff --git a/Lab 2/original_midi/MIDI-145.mid b/Lab 2/original_midi/MIDI-145.mid
new file mode 100644
index 0000000..c9f6517
Binary files /dev/null and b/Lab 2/original_midi/MIDI-145.mid differ
diff --git a/Lab 2/original_midi/MIDI-146.mid b/Lab 2/original_midi/MIDI-146.mid
new file mode 100644
index 0000000..7da09c7
Binary files /dev/null and b/Lab 2/original_midi/MIDI-146.mid differ
diff --git a/Lab 2/original_midi/MIDI-147.mid b/Lab 2/original_midi/MIDI-147.mid
new file mode 100644
index 0000000..5432170
Binary files /dev/null and b/Lab 2/original_midi/MIDI-147.mid differ
diff --git a/Lab 2/original_midi/MIDI-148.mid b/Lab 2/original_midi/MIDI-148.mid
new file mode 100644
index 0000000..6487415
Binary files /dev/null and b/Lab 2/original_midi/MIDI-148.mid differ
diff --git a/Lab 2/original_midi/MIDI-149.mid b/Lab 2/original_midi/MIDI-149.mid
new file mode 100644
index 0000000..5bd4760
Binary files /dev/null and b/Lab 2/original_midi/MIDI-149.mid differ
diff --git a/Lab 2/original_midi/MIDI-15.mid b/Lab 2/original_midi/MIDI-15.mid
new file mode 100644
index 0000000..f4e2bf3
Binary files /dev/null and b/Lab 2/original_midi/MIDI-15.mid differ
diff --git a/Lab 2/original_midi/MIDI-150.mid b/Lab 2/original_midi/MIDI-150.mid
new file mode 100644
index 0000000..0e70a80
Binary files /dev/null and b/Lab 2/original_midi/MIDI-150.mid differ
diff --git a/Lab 2/original_midi/MIDI-151.mid b/Lab 2/original_midi/MIDI-151.mid
new file mode 100644
index 0000000..09f87b2
Binary files /dev/null and b/Lab 2/original_midi/MIDI-151.mid differ
diff --git a/Lab 2/original_midi/MIDI-152.mid b/Lab 2/original_midi/MIDI-152.mid
new file mode 100644
index 0000000..15da5df
Binary files /dev/null and b/Lab 2/original_midi/MIDI-152.mid differ
diff --git a/Lab 2/original_midi/MIDI-153.mid b/Lab 2/original_midi/MIDI-153.mid
new file mode 100644
index 0000000..4db5cf9
Binary files /dev/null and b/Lab 2/original_midi/MIDI-153.mid differ
diff --git a/Lab 2/original_midi/MIDI-154.mid b/Lab 2/original_midi/MIDI-154.mid
new file mode 100644
index 0000000..a3f1dd8
Binary files /dev/null and b/Lab 2/original_midi/MIDI-154.mid differ
diff --git a/Lab 2/original_midi/MIDI-155.mid b/Lab 2/original_midi/MIDI-155.mid
new file mode 100644
index 0000000..7bfcadf
Binary files /dev/null and b/Lab 2/original_midi/MIDI-155.mid differ
diff --git a/Lab 2/original_midi/MIDI-156.mid b/Lab 2/original_midi/MIDI-156.mid
new file mode 100644
index 0000000..98f54cf
Binary files /dev/null and b/Lab 2/original_midi/MIDI-156.mid differ
diff --git a/Lab 2/original_midi/MIDI-157.mid b/Lab 2/original_midi/MIDI-157.mid
new file mode 100644
index 0000000..e526bcb
Binary files /dev/null and b/Lab 2/original_midi/MIDI-157.mid differ
diff --git a/Lab 2/original_midi/MIDI-158.mid b/Lab 2/original_midi/MIDI-158.mid
new file mode 100644
index 0000000..2927f3d
Binary files /dev/null and b/Lab 2/original_midi/MIDI-158.mid differ
diff --git a/Lab 2/original_midi/MIDI-159.mid b/Lab 2/original_midi/MIDI-159.mid
new file mode 100644
index 0000000..1be0f3a
Binary files /dev/null and b/Lab 2/original_midi/MIDI-159.mid differ
diff --git a/Lab 2/original_midi/MIDI-16.mid b/Lab 2/original_midi/MIDI-16.mid
new file mode 100644
index 0000000..d6c3b7d
Binary files /dev/null and b/Lab 2/original_midi/MIDI-16.mid differ
diff --git a/Lab 2/original_midi/MIDI-160.mid b/Lab 2/original_midi/MIDI-160.mid
new file mode 100644
index 0000000..7057c31
Binary files /dev/null and b/Lab 2/original_midi/MIDI-160.mid differ
diff --git a/Lab 2/original_midi/MIDI-161.mid b/Lab 2/original_midi/MIDI-161.mid
new file mode 100644
index 0000000..b204693
Binary files /dev/null and b/Lab 2/original_midi/MIDI-161.mid differ
diff --git a/Lab 2/original_midi/MIDI-162.mid b/Lab 2/original_midi/MIDI-162.mid
new file mode 100644
index 0000000..286f2aa
Binary files /dev/null and b/Lab 2/original_midi/MIDI-162.mid differ
diff --git a/Lab 2/original_midi/MIDI-163.mid b/Lab 2/original_midi/MIDI-163.mid
new file mode 100644
index 0000000..1571591
Binary files /dev/null and b/Lab 2/original_midi/MIDI-163.mid differ
diff --git a/Lab 2/original_midi/MIDI-164.mid b/Lab 2/original_midi/MIDI-164.mid
new file mode 100644
index 0000000..a42dc2c
Binary files /dev/null and b/Lab 2/original_midi/MIDI-164.mid differ
diff --git a/Lab 2/original_midi/MIDI-165.mid b/Lab 2/original_midi/MIDI-165.mid
new file mode 100644
index 0000000..d7f6c1d
Binary files /dev/null and b/Lab 2/original_midi/MIDI-165.mid differ
diff --git a/Lab 2/original_midi/MIDI-166.mid b/Lab 2/original_midi/MIDI-166.mid
new file mode 100644
index 0000000..3f3ca0a
Binary files /dev/null and b/Lab 2/original_midi/MIDI-166.mid differ
diff --git a/Lab 2/original_midi/MIDI-167.mid b/Lab 2/original_midi/MIDI-167.mid
new file mode 100644
index 0000000..26fb1cd
Binary files /dev/null and b/Lab 2/original_midi/MIDI-167.mid differ
diff --git a/Lab 2/original_midi/MIDI-168.mid b/Lab 2/original_midi/MIDI-168.mid
new file mode 100644
index 0000000..daa2bbc
Binary files /dev/null and b/Lab 2/original_midi/MIDI-168.mid differ
diff --git a/Lab 2/original_midi/MIDI-169.mid b/Lab 2/original_midi/MIDI-169.mid
new file mode 100644
index 0000000..15a6c62
Binary files /dev/null and b/Lab 2/original_midi/MIDI-169.mid differ
diff --git a/Lab 2/original_midi/MIDI-17.mid b/Lab 2/original_midi/MIDI-17.mid
new file mode 100644
index 0000000..38262d9
Binary files /dev/null and b/Lab 2/original_midi/MIDI-17.mid differ
diff --git a/Lab 2/original_midi/MIDI-170.mid b/Lab 2/original_midi/MIDI-170.mid
new file mode 100644
index 0000000..4ad3c15
Binary files /dev/null and b/Lab 2/original_midi/MIDI-170.mid differ
diff --git a/Lab 2/original_midi/MIDI-171.mid b/Lab 2/original_midi/MIDI-171.mid
new file mode 100644
index 0000000..f739396
Binary files /dev/null and b/Lab 2/original_midi/MIDI-171.mid differ
diff --git a/Lab 2/original_midi/MIDI-172.mid b/Lab 2/original_midi/MIDI-172.mid
new file mode 100644
index 0000000..fb99b34
Binary files /dev/null and b/Lab 2/original_midi/MIDI-172.mid differ
diff --git a/Lab 2/original_midi/MIDI-173.mid b/Lab 2/original_midi/MIDI-173.mid
new file mode 100644
index 0000000..0d26d82
Binary files /dev/null and b/Lab 2/original_midi/MIDI-173.mid differ
diff --git a/Lab 2/original_midi/MIDI-174.mid b/Lab 2/original_midi/MIDI-174.mid
new file mode 100644
index 0000000..6397b70
Binary files /dev/null and b/Lab 2/original_midi/MIDI-174.mid differ
diff --git a/Lab 2/original_midi/MIDI-175.mid b/Lab 2/original_midi/MIDI-175.mid
new file mode 100644
index 0000000..ff87ffc
Binary files /dev/null and b/Lab 2/original_midi/MIDI-175.mid differ
diff --git a/Lab 2/original_midi/MIDI-176.mid b/Lab 2/original_midi/MIDI-176.mid
new file mode 100644
index 0000000..a52afd5
Binary files /dev/null and b/Lab 2/original_midi/MIDI-176.mid differ
diff --git a/Lab 2/original_midi/MIDI-177.mid b/Lab 2/original_midi/MIDI-177.mid
new file mode 100644
index 0000000..a4ca4c8
Binary files /dev/null and b/Lab 2/original_midi/MIDI-177.mid differ
diff --git a/Lab 2/original_midi/MIDI-178.mid b/Lab 2/original_midi/MIDI-178.mid
new file mode 100644
index 0000000..15b5633
Binary files /dev/null and b/Lab 2/original_midi/MIDI-178.mid differ
diff --git a/Lab 2/original_midi/MIDI-179.mid b/Lab 2/original_midi/MIDI-179.mid
new file mode 100644
index 0000000..24b48f6
Binary files /dev/null and b/Lab 2/original_midi/MIDI-179.mid differ
diff --git a/Lab 2/original_midi/MIDI-18.mid b/Lab 2/original_midi/MIDI-18.mid
new file mode 100644
index 0000000..c28322a
Binary files /dev/null and b/Lab 2/original_midi/MIDI-18.mid differ
diff --git a/Lab 2/original_midi/MIDI-180.mid b/Lab 2/original_midi/MIDI-180.mid
new file mode 100644
index 0000000..bc316be
Binary files /dev/null and b/Lab 2/original_midi/MIDI-180.mid differ
diff --git a/Lab 2/original_midi/MIDI-181.mid b/Lab 2/original_midi/MIDI-181.mid
new file mode 100644
index 0000000..49809cd
Binary files /dev/null and b/Lab 2/original_midi/MIDI-181.mid differ
diff --git a/Lab 2/original_midi/MIDI-182.mid b/Lab 2/original_midi/MIDI-182.mid
new file mode 100644
index 0000000..d46dfbe
Binary files /dev/null and b/Lab 2/original_midi/MIDI-182.mid differ
diff --git a/Lab 2/original_midi/MIDI-183.mid b/Lab 2/original_midi/MIDI-183.mid
new file mode 100644
index 0000000..1e8d931
Binary files /dev/null and b/Lab 2/original_midi/MIDI-183.mid differ
diff --git a/Lab 2/original_midi/MIDI-184.mid b/Lab 2/original_midi/MIDI-184.mid
new file mode 100644
index 0000000..265c1a7
Binary files /dev/null and b/Lab 2/original_midi/MIDI-184.mid differ
diff --git a/Lab 2/original_midi/MIDI-185.mid b/Lab 2/original_midi/MIDI-185.mid
new file mode 100644
index 0000000..d816fa0
Binary files /dev/null and b/Lab 2/original_midi/MIDI-185.mid differ
diff --git a/Lab 2/original_midi/MIDI-186.mid b/Lab 2/original_midi/MIDI-186.mid
new file mode 100644
index 0000000..a328687
Binary files /dev/null and b/Lab 2/original_midi/MIDI-186.mid differ
diff --git a/Lab 2/original_midi/MIDI-187.mid b/Lab 2/original_midi/MIDI-187.mid
new file mode 100644
index 0000000..b3308b6
Binary files /dev/null and b/Lab 2/original_midi/MIDI-187.mid differ
diff --git a/Lab 2/original_midi/MIDI-188.mid b/Lab 2/original_midi/MIDI-188.mid
new file mode 100644
index 0000000..77c69ec
Binary files /dev/null and b/Lab 2/original_midi/MIDI-188.mid differ
diff --git a/Lab 2/original_midi/MIDI-189.mid b/Lab 2/original_midi/MIDI-189.mid
new file mode 100644
index 0000000..082045e
Binary files /dev/null and b/Lab 2/original_midi/MIDI-189.mid differ
diff --git a/Lab 2/original_midi/MIDI-19.mid b/Lab 2/original_midi/MIDI-19.mid
new file mode 100644
index 0000000..8ff5a6f
Binary files /dev/null and b/Lab 2/original_midi/MIDI-19.mid differ
diff --git a/Lab 2/original_midi/MIDI-190.mid b/Lab 2/original_midi/MIDI-190.mid
new file mode 100644
index 0000000..2031b8a
Binary files /dev/null and b/Lab 2/original_midi/MIDI-190.mid differ
diff --git a/Lab 2/original_midi/MIDI-191.mid b/Lab 2/original_midi/MIDI-191.mid
new file mode 100644
index 0000000..89b9ad8
Binary files /dev/null and b/Lab 2/original_midi/MIDI-191.mid differ
diff --git a/Lab 2/original_midi/MIDI-192.mid b/Lab 2/original_midi/MIDI-192.mid
new file mode 100644
index 0000000..e526bcb
Binary files /dev/null and b/Lab 2/original_midi/MIDI-192.mid differ
diff --git a/Lab 2/original_midi/MIDI-193.mid b/Lab 2/original_midi/MIDI-193.mid
new file mode 100644
index 0000000..34eac8b
Binary files /dev/null and b/Lab 2/original_midi/MIDI-193.mid differ
diff --git a/Lab 2/original_midi/MIDI-194.mid b/Lab 2/original_midi/MIDI-194.mid
new file mode 100644
index 0000000..e24eeea
Binary files /dev/null and b/Lab 2/original_midi/MIDI-194.mid differ
diff --git a/Lab 2/original_midi/MIDI-195.mid b/Lab 2/original_midi/MIDI-195.mid
new file mode 100644
index 0000000..7dd7f52
Binary files /dev/null and b/Lab 2/original_midi/MIDI-195.mid differ
diff --git a/Lab 2/original_midi/MIDI-196.mid b/Lab 2/original_midi/MIDI-196.mid
new file mode 100644
index 0000000..f940fc6
Binary files /dev/null and b/Lab 2/original_midi/MIDI-196.mid differ
diff --git a/Lab 2/original_midi/MIDI-197.mid b/Lab 2/original_midi/MIDI-197.mid
new file mode 100644
index 0000000..12a40b9
Binary files /dev/null and b/Lab 2/original_midi/MIDI-197.mid differ
diff --git a/Lab 2/original_midi/MIDI-198.mid b/Lab 2/original_midi/MIDI-198.mid
new file mode 100644
index 0000000..03506d9
Binary files /dev/null and b/Lab 2/original_midi/MIDI-198.mid differ
diff --git a/Lab 2/original_midi/MIDI-199.mid b/Lab 2/original_midi/MIDI-199.mid
new file mode 100644
index 0000000..1a2706c
Binary files /dev/null and b/Lab 2/original_midi/MIDI-199.mid differ
diff --git a/Lab 2/original_midi/MIDI-2.mid b/Lab 2/original_midi/MIDI-2.mid
new file mode 100644
index 0000000..ca456f4
Binary files /dev/null and b/Lab 2/original_midi/MIDI-2.mid differ
diff --git a/Lab 2/original_midi/MIDI-20.mid b/Lab 2/original_midi/MIDI-20.mid
new file mode 100644
index 0000000..e3396b3
Binary files /dev/null and b/Lab 2/original_midi/MIDI-20.mid differ
diff --git a/Lab 2/original_midi/MIDI-200.mid b/Lab 2/original_midi/MIDI-200.mid
new file mode 100644
index 0000000..e34c35b
Binary files /dev/null and b/Lab 2/original_midi/MIDI-200.mid differ
diff --git a/Lab 2/original_midi/MIDI-201.mid b/Lab 2/original_midi/MIDI-201.mid
new file mode 100644
index 0000000..b6292e6
Binary files /dev/null and b/Lab 2/original_midi/MIDI-201.mid differ
diff --git a/Lab 2/original_midi/MIDI-202.mid b/Lab 2/original_midi/MIDI-202.mid
new file mode 100644
index 0000000..9eaee07
Binary files /dev/null and b/Lab 2/original_midi/MIDI-202.mid differ
diff --git a/Lab 2/original_midi/MIDI-203.mid b/Lab 2/original_midi/MIDI-203.mid
new file mode 100644
index 0000000..7ed0d33
Binary files /dev/null and b/Lab 2/original_midi/MIDI-203.mid differ
diff --git a/Lab 2/original_midi/MIDI-204.mid b/Lab 2/original_midi/MIDI-204.mid
new file mode 100644
index 0000000..7cfe91b
Binary files /dev/null and b/Lab 2/original_midi/MIDI-204.mid differ
diff --git a/Lab 2/original_midi/MIDI-205.mid b/Lab 2/original_midi/MIDI-205.mid
new file mode 100644
index 0000000..9fa150d
Binary files /dev/null and b/Lab 2/original_midi/MIDI-205.mid differ
diff --git a/Lab 2/original_midi/MIDI-206.mid b/Lab 2/original_midi/MIDI-206.mid
new file mode 100644
index 0000000..8ae8433
Binary files /dev/null and b/Lab 2/original_midi/MIDI-206.mid differ
diff --git a/Lab 2/original_midi/MIDI-207.mid b/Lab 2/original_midi/MIDI-207.mid
new file mode 100644
index 0000000..6617747
Binary files /dev/null and b/Lab 2/original_midi/MIDI-207.mid differ
diff --git a/Lab 2/original_midi/MIDI-208.mid b/Lab 2/original_midi/MIDI-208.mid
new file mode 100644
index 0000000..5d898a2
Binary files /dev/null and b/Lab 2/original_midi/MIDI-208.mid differ
diff --git a/Lab 2/original_midi/MIDI-209.mid b/Lab 2/original_midi/MIDI-209.mid
new file mode 100644
index 0000000..be59f9f
Binary files /dev/null and b/Lab 2/original_midi/MIDI-209.mid differ
diff --git a/Lab 2/original_midi/MIDI-21.mid b/Lab 2/original_midi/MIDI-21.mid
new file mode 100644
index 0000000..95b928a
Binary files /dev/null and b/Lab 2/original_midi/MIDI-21.mid differ
diff --git a/Lab 2/original_midi/MIDI-210.mid b/Lab 2/original_midi/MIDI-210.mid
new file mode 100644
index 0000000..3c0cfd1
Binary files /dev/null and b/Lab 2/original_midi/MIDI-210.mid differ
diff --git a/Lab 2/original_midi/MIDI-211.mid b/Lab 2/original_midi/MIDI-211.mid
new file mode 100644
index 0000000..b03e2f5
Binary files /dev/null and b/Lab 2/original_midi/MIDI-211.mid differ
diff --git a/Lab 2/original_midi/MIDI-212.mid b/Lab 2/original_midi/MIDI-212.mid
new file mode 100644
index 0000000..a13b1a2
Binary files /dev/null and b/Lab 2/original_midi/MIDI-212.mid differ
diff --git a/Lab 2/original_midi/MIDI-213.mid b/Lab 2/original_midi/MIDI-213.mid
new file mode 100644
index 0000000..566cce9
Binary files /dev/null and b/Lab 2/original_midi/MIDI-213.mid differ
diff --git a/Lab 2/original_midi/MIDI-214.mid b/Lab 2/original_midi/MIDI-214.mid
new file mode 100644
index 0000000..de28b90
Binary files /dev/null and b/Lab 2/original_midi/MIDI-214.mid differ
diff --git a/Lab 2/original_midi/MIDI-215.mid b/Lab 2/original_midi/MIDI-215.mid
new file mode 100644
index 0000000..457d962
Binary files /dev/null and b/Lab 2/original_midi/MIDI-215.mid differ
diff --git a/Lab 2/original_midi/MIDI-216.mid b/Lab 2/original_midi/MIDI-216.mid
new file mode 100644
index 0000000..4d6f28e
Binary files /dev/null and b/Lab 2/original_midi/MIDI-216.mid differ
diff --git a/Lab 2/original_midi/MIDI-217.mid b/Lab 2/original_midi/MIDI-217.mid
new file mode 100644
index 0000000..e69f47c
Binary files /dev/null and b/Lab 2/original_midi/MIDI-217.mid differ
diff --git a/Lab 2/original_midi/MIDI-218.mid b/Lab 2/original_midi/MIDI-218.mid
new file mode 100644
index 0000000..7c8860e
Binary files /dev/null and b/Lab 2/original_midi/MIDI-218.mid differ
diff --git a/Lab 2/original_midi/MIDI-219.mid b/Lab 2/original_midi/MIDI-219.mid
new file mode 100644
index 0000000..df9018b
Binary files /dev/null and b/Lab 2/original_midi/MIDI-219.mid differ
diff --git a/Lab 2/original_midi/MIDI-22.mid b/Lab 2/original_midi/MIDI-22.mid
new file mode 100644
index 0000000..39bee3d
Binary files /dev/null and b/Lab 2/original_midi/MIDI-22.mid differ
diff --git a/Lab 2/original_midi/MIDI-220.mid b/Lab 2/original_midi/MIDI-220.mid
new file mode 100644
index 0000000..4cee476
Binary files /dev/null and b/Lab 2/original_midi/MIDI-220.mid differ
diff --git a/Lab 2/original_midi/MIDI-221.mid b/Lab 2/original_midi/MIDI-221.mid
new file mode 100644
index 0000000..699de66
Binary files /dev/null and b/Lab 2/original_midi/MIDI-221.mid differ
diff --git a/Lab 2/original_midi/MIDI-222.mid b/Lab 2/original_midi/MIDI-222.mid
new file mode 100644
index 0000000..9531c28
Binary files /dev/null and b/Lab 2/original_midi/MIDI-222.mid differ
diff --git a/Lab 2/original_midi/MIDI-223.mid b/Lab 2/original_midi/MIDI-223.mid
new file mode 100644
index 0000000..9c01803
Binary files /dev/null and b/Lab 2/original_midi/MIDI-223.mid differ
diff --git a/Lab 2/original_midi/MIDI-224.mid b/Lab 2/original_midi/MIDI-224.mid
new file mode 100644
index 0000000..02c47cf
Binary files /dev/null and b/Lab 2/original_midi/MIDI-224.mid differ
diff --git a/Lab 2/original_midi/MIDI-225.mid b/Lab 2/original_midi/MIDI-225.mid
new file mode 100644
index 0000000..a8f1ef7
Binary files /dev/null and b/Lab 2/original_midi/MIDI-225.mid differ
diff --git a/Lab 2/original_midi/MIDI-226.mid b/Lab 2/original_midi/MIDI-226.mid
new file mode 100644
index 0000000..3adcf60
Binary files /dev/null and b/Lab 2/original_midi/MIDI-226.mid differ
diff --git a/Lab 2/original_midi/MIDI-227.mid b/Lab 2/original_midi/MIDI-227.mid
new file mode 100644
index 0000000..69bb3f0
Binary files /dev/null and b/Lab 2/original_midi/MIDI-227.mid differ
diff --git a/Lab 2/original_midi/MIDI-228.mid b/Lab 2/original_midi/MIDI-228.mid
new file mode 100644
index 0000000..21a4857
Binary files /dev/null and b/Lab 2/original_midi/MIDI-228.mid differ
diff --git a/Lab 2/original_midi/MIDI-23.mid b/Lab 2/original_midi/MIDI-23.mid
new file mode 100644
index 0000000..3ba8c0c
Binary files /dev/null and b/Lab 2/original_midi/MIDI-23.mid differ
diff --git a/Lab 2/original_midi/MIDI-24.mid b/Lab 2/original_midi/MIDI-24.mid
new file mode 100644
index 0000000..8ff47fe
Binary files /dev/null and b/Lab 2/original_midi/MIDI-24.mid differ
diff --git a/Lab 2/original_midi/MIDI-25.mid b/Lab 2/original_midi/MIDI-25.mid
new file mode 100644
index 0000000..378ed76
Binary files /dev/null and b/Lab 2/original_midi/MIDI-25.mid differ
diff --git a/Lab 2/original_midi/MIDI-26.mid b/Lab 2/original_midi/MIDI-26.mid
new file mode 100644
index 0000000..7ab1027
Binary files /dev/null and b/Lab 2/original_midi/MIDI-26.mid differ
diff --git a/Lab 2/original_midi/MIDI-27.mid b/Lab 2/original_midi/MIDI-27.mid
new file mode 100644
index 0000000..f97c245
Binary files /dev/null and b/Lab 2/original_midi/MIDI-27.mid differ
diff --git a/Lab 2/original_midi/MIDI-28.mid b/Lab 2/original_midi/MIDI-28.mid
new file mode 100644
index 0000000..372d0d4
Binary files /dev/null and b/Lab 2/original_midi/MIDI-28.mid differ
diff --git a/Lab 2/original_midi/MIDI-29.mid b/Lab 2/original_midi/MIDI-29.mid
new file mode 100644
index 0000000..3600e89
Binary files /dev/null and b/Lab 2/original_midi/MIDI-29.mid differ
diff --git a/Lab 2/original_midi/MIDI-3.mid b/Lab 2/original_midi/MIDI-3.mid
new file mode 100644
index 0000000..8bc5f30
Binary files /dev/null and b/Lab 2/original_midi/MIDI-3.mid differ
diff --git a/Lab 2/original_midi/MIDI-30.mid b/Lab 2/original_midi/MIDI-30.mid
new file mode 100644
index 0000000..2630d21
Binary files /dev/null and b/Lab 2/original_midi/MIDI-30.mid differ
diff --git a/Lab 2/original_midi/MIDI-31.mid b/Lab 2/original_midi/MIDI-31.mid
new file mode 100644
index 0000000..a2f2f1b
Binary files /dev/null and b/Lab 2/original_midi/MIDI-31.mid differ
diff --git a/Lab 2/original_midi/MIDI-32.mid b/Lab 2/original_midi/MIDI-32.mid
new file mode 100644
index 0000000..141893f
Binary files /dev/null and b/Lab 2/original_midi/MIDI-32.mid differ
diff --git a/Lab 2/original_midi/MIDI-33.mid b/Lab 2/original_midi/MIDI-33.mid
new file mode 100644
index 0000000..b3a7157
Binary files /dev/null and b/Lab 2/original_midi/MIDI-33.mid differ
diff --git a/Lab 2/original_midi/MIDI-34.mid b/Lab 2/original_midi/MIDI-34.mid
new file mode 100644
index 0000000..a2d88e5
Binary files /dev/null and b/Lab 2/original_midi/MIDI-34.mid differ
diff --git a/Lab 2/original_midi/MIDI-35.mid b/Lab 2/original_midi/MIDI-35.mid
new file mode 100644
index 0000000..265f637
Binary files /dev/null and b/Lab 2/original_midi/MIDI-35.mid differ
diff --git a/Lab 2/original_midi/MIDI-36.mid b/Lab 2/original_midi/MIDI-36.mid
new file mode 100644
index 0000000..f1097b6
Binary files /dev/null and b/Lab 2/original_midi/MIDI-36.mid differ
diff --git a/Lab 2/original_midi/MIDI-37.mid b/Lab 2/original_midi/MIDI-37.mid
new file mode 100644
index 0000000..a9c3027
Binary files /dev/null and b/Lab 2/original_midi/MIDI-37.mid differ
diff --git a/Lab 2/original_midi/MIDI-38.mid b/Lab 2/original_midi/MIDI-38.mid
new file mode 100644
index 0000000..2e54f12
Binary files /dev/null and b/Lab 2/original_midi/MIDI-38.mid differ
diff --git a/Lab 2/original_midi/MIDI-39.mid b/Lab 2/original_midi/MIDI-39.mid
new file mode 100644
index 0000000..ec157f0
Binary files /dev/null and b/Lab 2/original_midi/MIDI-39.mid differ
diff --git a/Lab 2/original_midi/MIDI-4.mid b/Lab 2/original_midi/MIDI-4.mid
new file mode 100644
index 0000000..97b2247
Binary files /dev/null and b/Lab 2/original_midi/MIDI-4.mid differ
diff --git a/Lab 2/original_midi/MIDI-40.mid b/Lab 2/original_midi/MIDI-40.mid
new file mode 100644
index 0000000..bd235be
Binary files /dev/null and b/Lab 2/original_midi/MIDI-40.mid differ
diff --git a/Lab 2/original_midi/MIDI-41.mid b/Lab 2/original_midi/MIDI-41.mid
new file mode 100644
index 0000000..891e3aa
Binary files /dev/null and b/Lab 2/original_midi/MIDI-41.mid differ
diff --git a/Lab 2/original_midi/MIDI-42.mid b/Lab 2/original_midi/MIDI-42.mid
new file mode 100644
index 0000000..ca1a94a
Binary files /dev/null and b/Lab 2/original_midi/MIDI-42.mid differ
diff --git a/Lab 2/original_midi/MIDI-43.mid b/Lab 2/original_midi/MIDI-43.mid
new file mode 100644
index 0000000..c684739
Binary files /dev/null and b/Lab 2/original_midi/MIDI-43.mid differ
diff --git a/Lab 2/original_midi/MIDI-44.mid b/Lab 2/original_midi/MIDI-44.mid
new file mode 100644
index 0000000..2f482fc
Binary files /dev/null and b/Lab 2/original_midi/MIDI-44.mid differ
diff --git a/Lab 2/original_midi/MIDI-45.mid b/Lab 2/original_midi/MIDI-45.mid
new file mode 100644
index 0000000..ffe69e5
Binary files /dev/null and b/Lab 2/original_midi/MIDI-45.mid differ
diff --git a/Lab 2/original_midi/MIDI-46.mid b/Lab 2/original_midi/MIDI-46.mid
new file mode 100644
index 0000000..944ade5
Binary files /dev/null and b/Lab 2/original_midi/MIDI-46.mid differ
diff --git a/Lab 2/original_midi/MIDI-47.mid b/Lab 2/original_midi/MIDI-47.mid
new file mode 100644
index 0000000..25014e6
Binary files /dev/null and b/Lab 2/original_midi/MIDI-47.mid differ
diff --git a/Lab 2/original_midi/MIDI-48.mid b/Lab 2/original_midi/MIDI-48.mid
new file mode 100644
index 0000000..fcf572b
Binary files /dev/null and b/Lab 2/original_midi/MIDI-48.mid differ
diff --git a/Lab 2/original_midi/MIDI-49.mid b/Lab 2/original_midi/MIDI-49.mid
new file mode 100644
index 0000000..8ad8dc1
Binary files /dev/null and b/Lab 2/original_midi/MIDI-49.mid differ
diff --git a/Lab 2/original_midi/MIDI-5.mid b/Lab 2/original_midi/MIDI-5.mid
new file mode 100644
index 0000000..7ac6204
Binary files /dev/null and b/Lab 2/original_midi/MIDI-5.mid differ
diff --git a/Lab 2/original_midi/MIDI-50.mid b/Lab 2/original_midi/MIDI-50.mid
new file mode 100644
index 0000000..ab427c0
Binary files /dev/null and b/Lab 2/original_midi/MIDI-50.mid differ
diff --git a/Lab 2/original_midi/MIDI-51.mid b/Lab 2/original_midi/MIDI-51.mid
new file mode 100644
index 0000000..820b0ad
Binary files /dev/null and b/Lab 2/original_midi/MIDI-51.mid differ
diff --git a/Lab 2/original_midi/MIDI-52.mid b/Lab 2/original_midi/MIDI-52.mid
new file mode 100644
index 0000000..0cef29a
Binary files /dev/null and b/Lab 2/original_midi/MIDI-52.mid differ
diff --git a/Lab 2/original_midi/MIDI-53.mid b/Lab 2/original_midi/MIDI-53.mid
new file mode 100644
index 0000000..00e4328
Binary files /dev/null and b/Lab 2/original_midi/MIDI-53.mid differ
diff --git a/Lab 2/original_midi/MIDI-54.mid b/Lab 2/original_midi/MIDI-54.mid
new file mode 100644
index 0000000..7140fe9
Binary files /dev/null and b/Lab 2/original_midi/MIDI-54.mid differ
diff --git a/Lab 2/original_midi/MIDI-55.mid b/Lab 2/original_midi/MIDI-55.mid
new file mode 100644
index 0000000..a7b7ca2
Binary files /dev/null and b/Lab 2/original_midi/MIDI-55.mid differ
diff --git a/Lab 2/original_midi/MIDI-56.mid b/Lab 2/original_midi/MIDI-56.mid
new file mode 100644
index 0000000..5a0bb6d
Binary files /dev/null and b/Lab 2/original_midi/MIDI-56.mid differ
diff --git a/Lab 2/original_midi/MIDI-57.mid b/Lab 2/original_midi/MIDI-57.mid
new file mode 100644
index 0000000..60b8ea3
Binary files /dev/null and b/Lab 2/original_midi/MIDI-57.mid differ
diff --git a/Lab 2/original_midi/MIDI-58.mid b/Lab 2/original_midi/MIDI-58.mid
new file mode 100644
index 0000000..90f500f
Binary files /dev/null and b/Lab 2/original_midi/MIDI-58.mid differ
diff --git a/Lab 2/original_midi/MIDI-59.mid b/Lab 2/original_midi/MIDI-59.mid
new file mode 100644
index 0000000..128dbe9
Binary files /dev/null and b/Lab 2/original_midi/MIDI-59.mid differ
diff --git a/Lab 2/original_midi/MIDI-6.mid b/Lab 2/original_midi/MIDI-6.mid
new file mode 100644
index 0000000..47a5b38
Binary files /dev/null and b/Lab 2/original_midi/MIDI-6.mid differ
diff --git a/Lab 2/original_midi/MIDI-60.mid b/Lab 2/original_midi/MIDI-60.mid
new file mode 100644
index 0000000..19a52ca
Binary files /dev/null and b/Lab 2/original_midi/MIDI-60.mid differ
diff --git a/Lab 2/original_midi/MIDI-61.mid b/Lab 2/original_midi/MIDI-61.mid
new file mode 100644
index 0000000..2538754
Binary files /dev/null and b/Lab 2/original_midi/MIDI-61.mid differ
diff --git a/Lab 2/original_midi/MIDI-62.mid b/Lab 2/original_midi/MIDI-62.mid
new file mode 100644
index 0000000..99fbbe0
Binary files /dev/null and b/Lab 2/original_midi/MIDI-62.mid differ
diff --git a/Lab 2/original_midi/MIDI-63.mid b/Lab 2/original_midi/MIDI-63.mid
new file mode 100644
index 0000000..304b9e3
Binary files /dev/null and b/Lab 2/original_midi/MIDI-63.mid differ
diff --git a/Lab 2/original_midi/MIDI-64.mid b/Lab 2/original_midi/MIDI-64.mid
new file mode 100644
index 0000000..7e3bbc1
Binary files /dev/null and b/Lab 2/original_midi/MIDI-64.mid differ
diff --git a/Lab 2/original_midi/MIDI-65.mid b/Lab 2/original_midi/MIDI-65.mid
new file mode 100644
index 0000000..9bb6450
Binary files /dev/null and b/Lab 2/original_midi/MIDI-65.mid differ
diff --git a/Lab 2/original_midi/MIDI-66.mid b/Lab 2/original_midi/MIDI-66.mid
new file mode 100644
index 0000000..a593b11
Binary files /dev/null and b/Lab 2/original_midi/MIDI-66.mid differ
diff --git a/Lab 2/original_midi/MIDI-67.mid b/Lab 2/original_midi/MIDI-67.mid
new file mode 100644
index 0000000..f8f6ba6
Binary files /dev/null and b/Lab 2/original_midi/MIDI-67.mid differ
diff --git a/Lab 2/original_midi/MIDI-68.mid b/Lab 2/original_midi/MIDI-68.mid
new file mode 100644
index 0000000..6eeb380
Binary files /dev/null and b/Lab 2/original_midi/MIDI-68.mid differ
diff --git a/Lab 2/original_midi/MIDI-69.mid b/Lab 2/original_midi/MIDI-69.mid
new file mode 100644
index 0000000..6e7771c
Binary files /dev/null and b/Lab 2/original_midi/MIDI-69.mid differ
diff --git a/Lab 2/original_midi/MIDI-7.mid b/Lab 2/original_midi/MIDI-7.mid
new file mode 100644
index 0000000..5fee276
Binary files /dev/null and b/Lab 2/original_midi/MIDI-7.mid differ
diff --git a/Lab 2/original_midi/MIDI-70.mid b/Lab 2/original_midi/MIDI-70.mid
new file mode 100644
index 0000000..caf5dca
Binary files /dev/null and b/Lab 2/original_midi/MIDI-70.mid differ
diff --git a/Lab 2/original_midi/MIDI-71.mid b/Lab 2/original_midi/MIDI-71.mid
new file mode 100644
index 0000000..4bd0836
Binary files /dev/null and b/Lab 2/original_midi/MIDI-71.mid differ
diff --git a/Lab 2/original_midi/MIDI-72.mid b/Lab 2/original_midi/MIDI-72.mid
new file mode 100644
index 0000000..0e3d136
Binary files /dev/null and b/Lab 2/original_midi/MIDI-72.mid differ
diff --git a/Lab 2/original_midi/MIDI-73.mid b/Lab 2/original_midi/MIDI-73.mid
new file mode 100644
index 0000000..c7984a0
Binary files /dev/null and b/Lab 2/original_midi/MIDI-73.mid differ
diff --git a/Lab 2/original_midi/MIDI-74.mid b/Lab 2/original_midi/MIDI-74.mid
new file mode 100644
index 0000000..37080af
Binary files /dev/null and b/Lab 2/original_midi/MIDI-74.mid differ
diff --git a/Lab 2/original_midi/MIDI-75.mid b/Lab 2/original_midi/MIDI-75.mid
new file mode 100644
index 0000000..5f79695
Binary files /dev/null and b/Lab 2/original_midi/MIDI-75.mid differ
diff --git a/Lab 2/original_midi/MIDI-76.mid b/Lab 2/original_midi/MIDI-76.mid
new file mode 100644
index 0000000..74086fd
Binary files /dev/null and b/Lab 2/original_midi/MIDI-76.mid differ
diff --git a/Lab 2/original_midi/MIDI-77.mid b/Lab 2/original_midi/MIDI-77.mid
new file mode 100644
index 0000000..4361225
Binary files /dev/null and b/Lab 2/original_midi/MIDI-77.mid differ
diff --git a/Lab 2/original_midi/MIDI-78.mid b/Lab 2/original_midi/MIDI-78.mid
new file mode 100644
index 0000000..6f0d7f2
Binary files /dev/null and b/Lab 2/original_midi/MIDI-78.mid differ
diff --git a/Lab 2/original_midi/MIDI-79.mid b/Lab 2/original_midi/MIDI-79.mid
new file mode 100644
index 0000000..f4b499d
Binary files /dev/null and b/Lab 2/original_midi/MIDI-79.mid differ
diff --git a/Lab 2/original_midi/MIDI-8.mid b/Lab 2/original_midi/MIDI-8.mid
new file mode 100644
index 0000000..bb37abd
Binary files /dev/null and b/Lab 2/original_midi/MIDI-8.mid differ
diff --git a/Lab 2/original_midi/MIDI-80.mid b/Lab 2/original_midi/MIDI-80.mid
new file mode 100644
index 0000000..f90dbe8
Binary files /dev/null and b/Lab 2/original_midi/MIDI-80.mid differ
diff --git a/Lab 2/original_midi/MIDI-81.mid b/Lab 2/original_midi/MIDI-81.mid
new file mode 100644
index 0000000..b8b2f3a
Binary files /dev/null and b/Lab 2/original_midi/MIDI-81.mid differ
diff --git a/Lab 2/original_midi/MIDI-82.mid b/Lab 2/original_midi/MIDI-82.mid
new file mode 100644
index 0000000..c0552a6
Binary files /dev/null and b/Lab 2/original_midi/MIDI-82.mid differ
diff --git a/Lab 2/original_midi/MIDI-83.mid b/Lab 2/original_midi/MIDI-83.mid
new file mode 100644
index 0000000..aaada91
Binary files /dev/null and b/Lab 2/original_midi/MIDI-83.mid differ
diff --git a/Lab 2/original_midi/MIDI-84.mid b/Lab 2/original_midi/MIDI-84.mid
new file mode 100644
index 0000000..5cc1b30
Binary files /dev/null and b/Lab 2/original_midi/MIDI-84.mid differ
diff --git a/Lab 2/original_midi/MIDI-85.mid b/Lab 2/original_midi/MIDI-85.mid
new file mode 100644
index 0000000..009b2b8
Binary files /dev/null and b/Lab 2/original_midi/MIDI-85.mid differ
diff --git a/Lab 2/original_midi/MIDI-86.mid b/Lab 2/original_midi/MIDI-86.mid
new file mode 100644
index 0000000..5f66b41
Binary files /dev/null and b/Lab 2/original_midi/MIDI-86.mid differ
diff --git a/Lab 2/original_midi/MIDI-87.mid b/Lab 2/original_midi/MIDI-87.mid
new file mode 100644
index 0000000..4b4b588
Binary files /dev/null and b/Lab 2/original_midi/MIDI-87.mid differ
diff --git a/Lab 2/original_midi/MIDI-88.mid b/Lab 2/original_midi/MIDI-88.mid
new file mode 100644
index 0000000..734b362
Binary files /dev/null and b/Lab 2/original_midi/MIDI-88.mid differ
diff --git a/Lab 2/original_midi/MIDI-89.mid b/Lab 2/original_midi/MIDI-89.mid
new file mode 100644
index 0000000..d753ac6
Binary files /dev/null and b/Lab 2/original_midi/MIDI-89.mid differ
diff --git a/Lab 2/original_midi/MIDI-9.mid b/Lab 2/original_midi/MIDI-9.mid
new file mode 100644
index 0000000..ebdb77a
Binary files /dev/null and b/Lab 2/original_midi/MIDI-9.mid differ
diff --git a/Lab 2/original_midi/MIDI-90.mid b/Lab 2/original_midi/MIDI-90.mid
new file mode 100644
index 0000000..95b6cdb
Binary files /dev/null and b/Lab 2/original_midi/MIDI-90.mid differ
diff --git a/Lab 2/original_midi/MIDI-91.mid b/Lab 2/original_midi/MIDI-91.mid
new file mode 100644
index 0000000..9f09c46
Binary files /dev/null and b/Lab 2/original_midi/MIDI-91.mid differ
diff --git a/Lab 2/original_midi/MIDI-92.mid b/Lab 2/original_midi/MIDI-92.mid
new file mode 100644
index 0000000..e6cea1d
Binary files /dev/null and b/Lab 2/original_midi/MIDI-92.mid differ
diff --git a/Lab 2/original_midi/MIDI-93.mid b/Lab 2/original_midi/MIDI-93.mid
new file mode 100644
index 0000000..c8bed2c
Binary files /dev/null and b/Lab 2/original_midi/MIDI-93.mid differ
diff --git a/Lab 2/original_midi/MIDI-94.mid b/Lab 2/original_midi/MIDI-94.mid
new file mode 100644
index 0000000..e30f6c4
Binary files /dev/null and b/Lab 2/original_midi/MIDI-94.mid differ
diff --git a/Lab 2/original_midi/MIDI-95.mid b/Lab 2/original_midi/MIDI-95.mid
new file mode 100644
index 0000000..326665c
Binary files /dev/null and b/Lab 2/original_midi/MIDI-95.mid differ
diff --git a/Lab 2/original_midi/MIDI-96.mid b/Lab 2/original_midi/MIDI-96.mid
new file mode 100644
index 0000000..59bfe67
Binary files /dev/null and b/Lab 2/original_midi/MIDI-96.mid differ
diff --git a/Lab 2/original_midi/MIDI-97.mid b/Lab 2/original_midi/MIDI-97.mid
new file mode 100644
index 0000000..fcd9bd7
Binary files /dev/null and b/Lab 2/original_midi/MIDI-97.mid differ
diff --git a/Lab 2/original_midi/MIDI-98.mid b/Lab 2/original_midi/MIDI-98.mid
new file mode 100644
index 0000000..23d0f34
Binary files /dev/null and b/Lab 2/original_midi/MIDI-98.mid differ
diff --git a/Lab 2/original_midi/MIDI-99.mid b/Lab 2/original_midi/MIDI-99.mid
new file mode 100644
index 0000000..8e84aab
Binary files /dev/null and b/Lab 2/original_midi/MIDI-99.mid differ
diff --git a/Lab 2/utils/__init__.py b/Lab 2/utils/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/Lab 2/utils/__pycache__/__init__.cpython-37.pyc b/Lab 2/utils/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000..49eaa15
Binary files /dev/null and b/Lab 2/utils/__pycache__/__init__.cpython-37.pyc differ
diff --git a/Lab 2/utils/__pycache__/display_utils.cpython-37.pyc b/Lab 2/utils/__pycache__/display_utils.cpython-37.pyc
new file mode 100644
index 0000000..3a57bc4
Binary files /dev/null and b/Lab 2/utils/__pycache__/display_utils.cpython-37.pyc differ
diff --git a/Lab 2/utils/__pycache__/inference_utils.cpython-37.pyc b/Lab 2/utils/__pycache__/inference_utils.cpython-37.pyc
new file mode 100644
index 0000000..07a0473
Binary files /dev/null and b/Lab 2/utils/__pycache__/inference_utils.cpython-37.pyc differ
diff --git a/Lab 2/utils/__pycache__/metrics_utils.cpython-37.pyc b/Lab 2/utils/__pycache__/metrics_utils.cpython-37.pyc
new file mode 100644
index 0000000..ecef201
Binary files /dev/null and b/Lab 2/utils/__pycache__/metrics_utils.cpython-37.pyc differ
diff --git a/Lab 2/utils/__pycache__/midi_utils.cpython-37.pyc b/Lab 2/utils/__pycache__/midi_utils.cpython-37.pyc
new file mode 100644
index 0000000..bf23fba
Binary files /dev/null and b/Lab 2/utils/__pycache__/midi_utils.cpython-37.pyc differ
diff --git a/Lab 2/utils/__pycache__/path_utils.cpython-37.pyc b/Lab 2/utils/__pycache__/path_utils.cpython-37.pyc
new file mode 100644
index 0000000..e662aec
Binary files /dev/null and b/Lab 2/utils/__pycache__/path_utils.cpython-37.pyc differ
diff --git a/Lab 2/utils/display_utils.py b/Lab 2/utils/display_utils.py
new file mode 100644
index 0000000..1d5f510
--- /dev/null
+++ b/Lab 2/utils/display_utils.py
@@ -0,0 +1,182 @@
+# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import os
+import numpy as np
+import itertools
+import pretty_midi
+import matplotlib.pyplot as plt
+import matplotlib.gridspec as gridspec
+import moviepy.editor as mpy
+import music21
+from IPython.display import Video
+from IPython import display
+import seaborn as sns
+
+# --- plot------------------------------------------------------------------
+
+
+def plot_loss_logs(G_loss, D_loss, figsize=(15, 5), smoothing=0.001):
+ """Utility for plotting losses with smoothing."""
+ plt.ion()
+ sns.set()
+ plt.figure(figsize=figsize)
+ plt.plot(D_loss, label='C_loss')
+ plt.plot(G_loss, label='G_loss')
+ plt.legend(loc='lower right', fontsize='medium')
+ plt.xlabel('Iteration', fontsize='x-large')
+ plt.ylabel('Losses', fontsize='x-large')
+ plt.title('Training History', fontsize='xx-large')
+
+
+def playmidi(filename):
+ mf = music21.midi.MidiFile()
+ mf.open(filename)
+ mf.read()
+ mf.close()
+ s = music21.midi.translate.midiFileToStream(mf)
+ s.show('midi')
+
+def show_pianoroll(xs, min_pitch=45, max_pitch=85,
+ programs = [0, 0, 0, 0], save_dir=None):
+ """ Plot a MultiTrack PianoRoll
+
+ :param x: Multi Instrument PianoRoll Tensor
+ :param min_pitch: Min Pitch / Min Y across all instruments.
+ :param max_pitch: Max Pitch / Max Y across all instruments.
+ :param programs: Program Number of the Tracks.
+ :param file_name: Optional. File Name to save the plot.
+ :return:
+ """
+
+ # Convert fake_x to numpy and convert -1 to 0
+ xs = xs > 0
+
+ channel_last = lambda x: np.moveaxis(np.array(x), 2, 0)
+ xs = [channel_last(x) for x in xs]
+
+ assert len(xs[0].shape) == 3, 'Pianoroll shape must have 3 dims, Got %d' % len(xs[0].shape)
+ n_tracks, time_step, _ = xs[0].shape
+
+ plt.ion()
+ fig = plt.figure(figsize=(15, 4))
+
+ x = xs[0]
+
+ for j in range(4):
+ b = j+1
+ ax = fig.add_subplot(1,4,b)
+ nz = np.nonzero(x[b-1])
+
+ if programs:
+ ax.set_xlabel('Time('+pretty_midi.program_to_instrument_class(programs[j%4])+')')
+
+ if (j+1)== 1:
+ ax.set_ylabel('Pitch')
+ else:
+ ax.set_yticks([])
+
+ ax.scatter(nz[0], nz[1], s=np.pi * 3, color='bgrcmk'[b-1])
+ ax.set_ylim(45, 85)
+ ax.set_xlim(0, time_step)
+ fig.add_subplot(ax)
+
+
+def plot_pianoroll(iteration, xs, fake_xs, min_pitch=45, max_pitch=85,
+ programs = [0, 0, 0, 0], save_dir=None):
+ """ Plot a MultiTrack PianoRoll
+
+ :param x: Multi Instrument PianoRoll Tensor
+ :param min_pitch: Min Pitch / Min Y across all instruments.
+ :param max_pitch: Max Pitch / Max Y across all instruments.
+ :param programs: Program Number of the Tracks.
+ :param file_name: Optional. File Name to save the plot.
+ :return:
+ """
+
+ # Convert fake_x to numpy and convert -1 to 0
+ xs = xs > 0
+ fake_xs = fake_xs > 0
+
+ channel_last = lambda x: np.moveaxis(np.array(x), 2, 0)
+ xs = [channel_last(x) for x in xs]
+ fake_xs = [channel_last(fake_x) for fake_x in fake_xs]
+
+ assert len(xs[0].shape) == 3, 'Pianoroll shape must have 3 dims, Got %d' % len(xs[0].shape)
+ n_tracks, time_step, _ = xs[0].shape
+
+ plt.ion()
+ fig = plt.figure(figsize=(15, 8))
+
+ # gridspec inside gridspec
+ outer_grid = gridspec.GridSpec(2, 2, wspace=0.1, hspace=0.2)
+
+ for i in range(4):
+ inner_grid = gridspec.GridSpecFromSubplotSpec(2, n_tracks,
+ subplot_spec=outer_grid[i], wspace=0.0, hspace=0.0)
+
+ x, fake_x = xs[i], fake_xs[i]
+
+ for j, (a, b) in enumerate(itertools.product([1, 2], [1, 2, 3, 4])):
+
+ ax = fig.add_subplot(inner_grid[j])
+
+ if a == 1:
+ nz = np.nonzero(x[b-1])
+ else:
+ nz = np.nonzero(fake_x[b-1])
+
+ if programs:
+ ax.set_xlabel('Time('+pretty_midi.program_to_instrument_class(programs[j%4])+')')
+
+ if b == 1:
+ ax.set_ylabel('Pitch')
+ else:
+ ax.set_yticks([])
+
+ ax.scatter(nz[0], nz[1], s=np.pi * 3, color='bgrcmk'[b-1])
+ ax.set_ylim(45, 85)
+ ax.set_xlim(0, time_step)
+ fig.add_subplot(ax)
+
+ if isinstance(iteration, int):
+ plt.suptitle('iteration: {}'.format(iteration), fontsize=20)
+ filename = os.path.join(save_dir, 'sample_iteration_%05d.png' % iteration)
+ else:
+ plt.suptitle('Inference', fontsize=20)
+ filename = os.path.join(save_dir, 'sample_inference.png')
+ plt.savefig(filename)
+ plt.close(fig)
+
+def display_loss(iteration, d_losses, g_losses):
+ sns.set()
+ display.clear_output(wait=True)
+ fig = plt.figure(figsize=(15,5))
+ line1, = plt.plot(range(iteration+1), d_losses, 'r')
+ line2, = plt.plot(range(iteration+1), g_losses, 'k')
+ plt.xlabel('Iterations')
+ plt.ylabel('Losses')
+ plt.legend((line1, line2), ('C-loss', 'G-loss'))
+
+ return display.display(fig)
+
+
+def make_training_video(folder_dir):
+ files = sorted([os.path.join(folder_dir, f) for f in os.listdir(folder_dir) if f.endswith('.png')])
+ frames = [mpy.ImageClip(f).set_duration(1) for f in files]
+ clip = mpy.concatenate_videoclips(frames, method="compose")
+ clip.write_videofile("movie.mp4",fps=15)
+ return Video("movie.mp4")
+
\ No newline at end of file
diff --git a/Lab 2/utils/inference_utils.py b/Lab 2/utils/inference_utils.py
new file mode 100644
index 0000000..90c01fd
--- /dev/null
+++ b/Lab 2/utils/inference_utils.py
@@ -0,0 +1,61 @@
+# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import tensorflow as tf
+import numpy as np
+
+from utils import path_utils, midi_utils, display_utils
+
+# --- local samples------------------------------------------------------------------
+
+def load_melody_samples(n_sample=10):
+ """Load the samples used for evaluation."""
+
+ sample_source_path = './dataset/eval.npy'
+
+ data = np.load(sample_source_path)
+ data = np.asarray(data, dtype=np.float32) # {-1, 1}
+
+ random_idx = np.random.choice(len(data), n_sample, replace=False)
+
+ sample_x = data[random_idx]
+
+ sample_z = tf.random.truncated_normal((n_sample, 2, 8, 512))
+
+ print("Loaded {} melody samples".format(len(sample_x)))
+
+ return sample_x, sample_z
+
+# --- Training ------------------------------------------------------------------
+
+def generate_pianoroll(generator, conditioned_track, noise_vector=None):
+ if noise_vector == None:
+ noise_vector = tf.random.truncated_normal((1, 2, 8, 512))
+ return generator((conditioned_track, noise_vector), training=False)
+
+
+def generate_midi(generator, saveto_dir, input_midi_file='./Experiments/data/happy_birthday_easy.mid'):
+ conditioned_track = midi_utils.get_conditioned_track(midi=input_midi_file)
+ generated_pianoroll = generate_pianoroll(generator, conditioned_track)
+
+ destination_path = path_utils.new_temp_midi_path(saveto_dir=saveto_dir)
+ midi_utils.save_pianoroll_as_midi(generated_pianoroll.numpy(), destination_path=destination_path)
+ return destination_path
+
+def show_generated_pianorolls(generator, eval_dir, input_midi_file='./Experiments/data/happy_birthday_easy.mid', n_pr = 4):
+ conditioned_track = midi_utils.get_conditioned_track(midi=input_midi_file)
+ for i in range(n_pr):
+ generated_pianoroll = generate_pianoroll(generator, conditioned_track)
+ display_utils.show_pianoroll(generated_pianoroll)
\ No newline at end of file
diff --git a/Lab 2/utils/metrics_utils.py b/Lab 2/utils/metrics_utils.py
new file mode 100644
index 0000000..362fb4b
--- /dev/null
+++ b/Lab 2/utils/metrics_utils.py
@@ -0,0 +1,198 @@
+# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import numpy as np
+import matplotlib.pyplot as plt
+import pickle
+import seaborn as sns
+
+
+# --- Metrics ------------------------------------------------------------------
+class EmptyBarRateMetricCreator:
+ label = "Empty Bar Rate"
+ description = """The ratio of empty bars to the total number of bars."""
+
+ def compute(self, pianoroll):
+ if len(pianoroll.shape) != 5:
+ raise ValueError("Input pianoroll must have 5 dimensions.")
+ return np.mean(
+ np.any(pianoroll > 0.5, (2, 3)).astype(np.float32), (0, 1))
+
+class UniquePitchCountMetricCreator:
+ label = "Unique Pitch Count"
+ description = """The number of unique pitches used per bar."""
+
+ def compute(self, pianoroll):
+ if len(pianoroll.shape) != 5:
+ raise ValueError("Input pianoroll must have 5 dimensions.")
+ pitch_hist = np.mean(np.sum(pianoroll, 2), (0, 1))
+ return np.linalg.norm(np.ones(pitch_hist.shape)-pitch_hist, axis=0) #Sums across each timestep in bar
+
+class UniquePitchClassCountMetricCreator:
+ label = "Unique Pitch Class Count"
+ description = """
+ Average number of notes in each bar after projecting to chroma space.
+ Chroma features or Pitch Class Profiles are a distribution of the signal’s energy
+ across a predefined set of pitch classes.
+ """
+
+ def _to_chroma(self, pianoroll):
+ """Return the chroma features (not normalized)."""
+ if len(pianoroll.shape) != 5:
+ raise ValueError("Input pianoroll must have 5 dimensions.")
+ remainder = pianoroll.shape[3] % 12
+ if remainder:
+ pianoroll = np.pad(
+ pianoroll, ((0, 0), (0, 0), (0, 0), (0, 12 - remainder), (0, 0)))
+ reshaped = np.reshape(
+ pianoroll, (-1, pianoroll.shape[1], pianoroll.shape[2], 12,
+ pianoroll.shape[3] // 12 + int(remainder > 0),
+ pianoroll.shape[4]))
+ return np.sum(reshaped, 4)
+
+ def compute(self, pianoroll):
+ if len(pianoroll.shape) != 5:
+ raise ValueError("Input pianoroll must have 5 dimensions.")
+
+ chroma_pianoroll = self._to_chroma(pianoroll)
+ pitch_hist = np.mean(np.sum(chroma_pianoroll, 2), (0, 1))
+ return np.linalg.norm(np.ones(pitch_hist.shape)-pitch_hist, axis=0) #Sums across each timestep in bar
+
+
+class PolyphonicRateMetricCreator:
+ label = "Polyphonic Rate"
+ description = """
+ The ratio of the number of time steps where the number of pitches
+ being played is larger than `threshold` to the total number of time steps.
+ """
+ def __init__(self, threshold=2):
+ self.threshold = threshold
+
+ def compute(self, pianoroll):
+ if len(pianoroll.shape) != 5:
+ raise ValueError("Input pianoroll must have 5 dimensions.")
+ n_poly = np.count_nonzero((np.count_nonzero(pianoroll, 3) > self.threshold), 2)
+ return np.mean((n_poly / pianoroll.shape[2]), (0, 1))
+
+class InScaleRateMetricCreator:
+ label = "In Scale Rate"
+ description = """
+ The ratio of the average number of notes in a bar, which are in C major key which
+ is the most common key found in music to the total number of notes.
+ """
+
+ def _to_chroma(self, pianoroll):
+ """Return the chroma features (not normalized)."""
+ if len(pianoroll.shape) != 5:
+ raise ValueError("Input pianoroll must have 5 dimensions.")
+ remainder = pianoroll.shape[3] % 12
+ if remainder:
+ pianoroll = np.pad(
+ pianoroll, ((0, 0), (0, 0), (0, 0), (0, 12 - remainder), (0, 0)))
+ reshaped = np.reshape(
+ pianoroll, (-1, pianoroll.shape[1], pianoroll.shape[2], 12,
+ pianoroll.shape[3] // 12 + int(remainder > 0),
+ pianoroll.shape[4]))
+ return np.sum(reshaped, 4)
+
+ def _scale_mask(self, key=3):
+ """Return a scale mask for the given key. Default to C major scale."""
+ a_scale_mask = np.array([[[1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0]]], bool)
+ return np.expand_dims(np.roll(a_scale_mask, -key, 2), -1).astype(np.float32)
+
+ def compute(self, pianoroll):
+ if len(pianoroll.shape) != 5:
+ raise ValueError("Input pianoroll must have 5 dimensions.")
+
+ chroma_pianoroll = self._to_chroma(pianoroll)
+ in_scale = np.sum(self._scale_mask() * np.sum(chroma_pianoroll, 2), (0, 1, 2))
+ return in_scale / np.sum(chroma_pianoroll, (0, 1, 2, 3))
+
+class MusicQualityMetricsManager:
+
+ def __init__(self, metrics_creators):
+ self.metrics_creators = metrics_creators
+ self.initialize()
+
+ def initialize(self):
+ self.metrics = {}
+ for metrics_creator in self.metrics_creators:
+ self.metrics[metrics_creator] = {'reference': None, 'per_iteration': []}
+
+ def _reshape_pianoroll(self, pianoroll):
+ return pianoroll.reshape((-1,2,16,128,4))[:,:,:,24:108,:]
+
+ def append_metrics_for_iteration(self, pianoroll, iteration):
+ reshaped_pianoroll = self._reshape_pianoroll(pianoroll)
+ for metric_creator in self.metrics.keys():
+ metric = metric_creator.compute(reshaped_pianoroll)
+ self.metrics[metric_creator]['per_iteration'].append((iteration, metric))
+
+ def set_reference_metrics(self, pianoroll):
+ reshaped_pianoroll = self._reshape_pianoroll(pianoroll)
+ for metric_creator in self.metrics.keys():
+ metric = metric_creator.compute(reshaped_pianoroll)
+ self.metrics[metric_creator]['reference'] = metric
+
+ def plot_metrics(self):
+ num_instruments = 4
+ plt.ion()
+ sns.set()
+ fig, axs = plt.subplots(len(self.metrics), num_instruments, sharex=True, figsize=(60, 30))
+ fig.tight_layout()
+ plt.xscale('log')
+
+ for instrument_idx in range(num_instruments):
+ for metric_idx, metric_creator in enumerate(self.metrics):
+ axs[metric_idx][instrument_idx].tick_params(axis='both', which='major', labelsize=30)
+ axs[metric_idx][instrument_idx].tick_params(axis='both', which='minor', labelsize=30)
+
+ metric_data = self.metrics[metric_creator]
+
+ # Plot reference line
+ axs[metric_idx][instrument_idx].plot(
+ [x[0] for x in metric_data['per_iteration']],
+ np.ones(len(metric_data['per_iteration'])) * metric_data['reference'][instrument_idx],
+ 'r',
+ linewidth=10,
+ alpha=0.7
+ )
+
+ # Plot per-iteration metrics
+ axs[metric_idx][instrument_idx].scatter(
+ [x[0] for x in metric_data['per_iteration']],
+ [x[1][instrument_idx] for x in metric_data['per_iteration']],
+ linewidth=10
+ )
+
+
+ for instrument_idx in range(num_instruments):
+ label = "Iterations (Instrument {})".format(instrument_idx)
+ axs[2][instrument_idx].set_xlabel(xlabel=label,fontsize=40)
+
+ for metric_idx, metric_creator in enumerate(self.metrics):
+ label = metric_creator.label
+ axs[metric_idx][0].set_ylabel(ylabel=label,fontsize=40)
+
+ plt.show()
+
+
+
+DEFAULT_METRICS_CREATORS = [
+ EmptyBarRateMetricCreator(),
+ UniquePitchCountMetricCreator(),
+ InScaleRateMetricCreator()
+]
+metrics_manager = MusicQualityMetricsManager(DEFAULT_METRICS_CREATORS)
\ No newline at end of file
diff --git a/Lab 2/utils/midi_utils.py b/Lab 2/utils/midi_utils.py
new file mode 100644
index 0000000..351bb58
--- /dev/null
+++ b/Lab 2/utils/midi_utils.py
@@ -0,0 +1,74 @@
+# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import tensorflow as tf
+import numpy as np
+import pypianoroll
+
+def save_pianoroll_as_midi(pianoroll,
+ programs=[0, 0, 0, 0],
+ is_drums=[False, False, False, False],
+ tempo=100, # in bpm
+ beat_resolution=4, # number of time steps
+ destination_path=None
+ ):
+
+ pianoroll = pianoroll > 0
+
+ # Reshape batched pianoroll array to a single pianoroll array
+ pianoroll_ = pianoroll.reshape((-1, pianoroll.shape[2], pianoroll.shape[3]))
+
+ # Create the tracks
+ tracks = []
+ for idx in range(pianoroll_.shape[2]):
+ tracks.append(pypianoroll.Track(
+ pianoroll_[..., idx], programs[idx], is_drums[idx]))
+
+ multitrack = pypianoroll.Multitrack(
+ tracks=tracks, tempo=tempo, beat_resolution=beat_resolution)
+
+ multitrack.write(destination_path)
+ print('Midi saved to ', destination_path)
+ return destination_path
+
+
+def get_conditioned_track(midi=None, phrase_length=32, beat_resolution=4):
+
+ if not isinstance(midi, str):
+ # ----------- Generation from preprocessed dataset ------------------
+ sample_x = midi
+ sample_c = np.expand_dims(sample_x[..., 0], -1)
+ else:
+ # --------------- Generation from midi file -------------------------
+ midi_file = midi
+ parsed = pypianoroll.Multitrack(beat_resolution=beat_resolution)
+ parsed.parse_midi(midi_file)
+
+ sample_c = parsed.tracks[0].pianoroll.astype(np.float32)
+
+ # Remove initial steps that have no note-on events
+ first_non_zero = np.nonzero(sample_c.sum(axis=1))[0][0]
+
+ # Use the first 'phrase_length' steps as the primer
+ sample_c = sample_c[first_non_zero: first_non_zero + phrase_length]
+
+ # Binarize data (ignore velocity value)
+ sample_c[sample_c > 0] = 1
+ sample_c[sample_c <= 0] = -1
+
+ sample_c = np.expand_dims(np.expand_dims(sample_c, 0), -1) # 1, 32, 128, 1
+
+ sample_c = tf.convert_to_tensor(sample_c, dtype=tf.float32)
+ return sample_c
diff --git a/Lab 2/utils/path_utils.py b/Lab 2/utils/path_utils.py
new file mode 100644
index 0000000..8175c4e
--- /dev/null
+++ b/Lab 2/utils/path_utils.py
@@ -0,0 +1,24 @@
+# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+# the Software, and to permit persons to whom the Software is furnished to do so.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import os
+import glob
+
+def generated_midi_path_for_iteration(iteration, saveto_dir=None):
+ return os.path.join(saveto_dir, 'iteration-{}.mid'.format(iteration))
+
+def new_temp_midi_path(saveto_dir=None):
+ mid_files = glob.glob(os.path.join(saveto_dir, 'temp-*.mid'))
+ return os.path.join(saveto_dir, 'temp-%d.mid' % len(mid_files))