{ "cells": [ { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "view-in-github" }, "source": [ "\"Open" ] }, { "cell_type": "markdown", "metadata": { "id": "2ODTNI8L-2jb" }, "source": [ "# Exercise 1: Comparing Different Types of Recurrent and Convolutional Neural Networks to Compose Bach Chorales" ] }, { "cell_type": "markdown", "metadata": { "id": "qnIEa8B29vSO" }, "source": [ "![joey-huang-XBh4DOGqMfc-unsplash.jpg](data:image/jpeg;base64,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)" ] }, { "cell_type": "markdown", "metadata": { "id": "5xU0vb9p99PZ" }, "source": [ "Can you compose a new [Bach chorale](https://en.wikipedia.org/wiki/List_of_chorale_harmonisations_by_Johann_Sebastian_Bach) using recurrent and/or convolutional neural networks? 🎼 🎶 🎹" ] }, { "cell_type": "markdown", "metadata": { "id": "YasolsLS9j5J" }, "source": [ "**Source**: Photo by Joey Huang on Unsplash\n", "\n", "This exercise adapts Géron et al.'s Jupyter notebook exercises for [chapter 15](https://github.com/ageron/handson-ml2/blob/master/15_processing_sequences_using_rnns_and_cnns.ipynb) \\([License](https://github.com/ageron/handson-ml2/blob/master/LICENSE)) of his book [\"Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow, 2nd Edition\"](https://www.oreilly.com/library/view/hands-on-machine-learning/9781492032632/).\n", " " ] }, { "cell_type": "markdown", "metadata": { "id": "OiXkBRxxMRgA" }, "source": [ "## Part I: Setup" ] }, { "cell_type": "markdown", "metadata": { "id": "_9mM0nmxMRgA" }, "source": [ "First, let's import a few common modules, ensure MatplotLib plots figures inline and prepare a function to save the figures. We also check that Python 3.5 or later is installed (although Python 2.x may work, it is deprecated so we strongly recommend you use Python 3 instead), as well as Scikit-Learn ≥0.20 and TensorFlow ≥2.0." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "RDH9bERJMRgA" }, "outputs": [], "source": [ "# Python ≥3.5 is required\n", "import sys\n", "assert sys.version_info >= (3, 5)\n", "\n", "# Is this notebook running on Colab or Kaggle?\n", "IS_COLAB = \"google.colab\" in sys.modules\n", "IS_KAGGLE = \"kaggle_secrets\" in sys.modules\n", "\n", "# Scikit-Learn ≥0.20 is required\n", "import sklearn\n", "assert sklearn.__version__ >= \"0.20\"\n", "\n", "# TensorFlow ≥2.0 is required\n", "import tensorflow as tf\n", "from tensorflow import keras\n", "assert tf.__version__ >= \"2.0\"\n", "\n", "if not tf.config.list_physical_devices('GPU'):\n", " print(\"No GPU was detected. LSTMs and CNNs can be very slow without a GPU.\")\n", " if IS_COLAB:\n", " print(\"Go to Runtime > Change runtime and select a GPU hardware accelerator.\")\n", " if IS_KAGGLE:\n", " print(\"Go to Settings > Accelerator and select GPU.\")\n", "\n", "# Common imports\n", "import numpy as np\n", "import os\n", "from pathlib import Path\n", "\n", "# to make this notebook's output stable across runs\n", "np.random.seed(42)\n", "tf.random.set_seed(42)\n", "\n", "# To plot pretty figures\n", "%matplotlib inline\n", "import matplotlib as mpl\n", "import matplotlib.pyplot as plt\n", "mpl.rc('axes', labelsize=14)\n", "mpl.rc('xtick', labelsize=12)\n", "mpl.rc('ytick', labelsize=12)\n", "\n", "# Where to save the figures\n", "PROJECT_ROOT_DIR = \".\"\n", "CHAPTER_ID = \"rnn\"\n", "IMAGES_PATH = os.path.join(PROJECT_ROOT_DIR, \"images\", CHAPTER_ID)\n", "os.makedirs(IMAGES_PATH, exist_ok=True)\n", "\n", "def save_fig(fig_id, tight_layout=True, fig_extension=\"png\", resolution=300):\n", " path = os.path.join(IMAGES_PATH, fig_id + \".\" + fig_extension)\n", " print(\"Saving figure\", fig_id)\n", " if tight_layout:\n", " plt.tight_layout()\n", " plt.savefig(path, format=fig_extension, dpi=resolution)\n", "\n", "# Loading Tensorboard\n", "%load_ext tensorboard" ] }, { "cell_type": "markdown", "metadata": { "id": "uQy9j2q-M9bn" }, "source": [ "Let's import two more libraries:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "bgyr-cIrM-_d" }, "outputs": [], "source": [ "import pooch # Import the pooch library to load data from URL\n", "import pandas as pd # Import the pandas library to handle arrays" ] }, { "cell_type": "markdown", "metadata": { "id": "Qgb5ri9iMAvl" }, "source": [ "Second, let's load the data:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "ebyV8I_TCRgC" }, "outputs": [], "source": [ "url = \"https://unils-my.sharepoint.com/:u:/g/personal/tom_beucler_unil_ch/EdQBrnnm_kJLhEYL4ZEaTxAB0XlVYiQrXtDRUKMxHZVIlg?download=1\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "DnXIqfMMDDJA" }, "outputs": [], "source": [ "files = pooch.retrieve(url,processor=pooch.Unzip(),known_hash='57b0aa3c1716e862b9ab9a941d516b88841c350a08ee216027ecb69f59f442a0')" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "sovRibEkAdVf" }, "outputs": [], "source": [ "# Finds the directory containing the files and ...\n", "jsb_chorales_dir = Path(files[0]).parent.parent\n", "\n", "# ... Sort these files into training/validation/test\n", "train_files = sorted(jsb_chorales_dir.glob(\"train/chorale_*.csv\"))\n", "valid_files = sorted(jsb_chorales_dir.glob(\"valid/chorale_*.csv\"))\n", "test_files = sorted(jsb_chorales_dir.glob(\"test/chorale_*.csv\"))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "MBBVvZR4AdVg" }, "outputs": [], "source": [ "# Load the chorales from the training, validation, and test set\n", "def load_chorales(filepaths):\n", " return [pd.read_csv(filepath).values.tolist() for filepath in filepaths]\n", "\n", "train_chorales = load_chorales(train_files)\n", "valid_chorales = load_chorales(valid_files)\n", "test_chorales = load_chorales(test_files)" ] }, { "cell_type": "markdown", "metadata": { "id": "U21DQCAJNoA8" }, "source": [ "Third, let's define the functions Géron implemented to listen to these chorales. According to Géron:\n", "\n", "\"*You don't need to understand the details here, and in fact there are certainly simpler ways to do this, for example using MIDI players, but I just wanted to have a bit of fun writing a synthesizer.*\"\n", "\n", "" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "4aSInW7RNl0O" }, "outputs": [], "source": [ "from IPython.display import Audio\n", "\n", "def notes_to_frequencies(notes):\n", " # Frequency doubles when you go up one octave; there are 12 semi-tones\n", " # per octave; Note A on octave 4 is 440 Hz, and it is note number 69.\n", " return 2 ** ((np.array(notes) - 69) / 12) * 440\n", "\n", "def frequencies_to_samples(frequencies, tempo, sample_rate):\n", " note_duration = 60 / tempo # the tempo is measured in beats per minutes\n", " # To reduce click sound at every beat, we round the frequencies to try to\n", " # get the samples close to zero at the end of each note.\n", " frequencies = np.round(note_duration * frequencies) / note_duration\n", " n_samples = int(note_duration * sample_rate)\n", " time = np.linspace(0, note_duration, n_samples)\n", " sine_waves = np.sin(2 * np.pi * frequencies.reshape(-1, 1) * time)\n", " # Removing all notes with frequencies ≤ 9 Hz (includes note 0 = silence)\n", " sine_waves *= (frequencies > 9.).reshape(-1, 1)\n", " return sine_waves.reshape(-1)\n", "\n", "def chords_to_samples(chords, tempo, sample_rate):\n", " freqs = notes_to_frequencies(chords)\n", " freqs = np.r_[freqs, freqs[-1:]] # make last note a bit longer\n", " merged = np.mean([frequencies_to_samples(melody, tempo, sample_rate)\n", " for melody in freqs.T], axis=0)\n", " n_fade_out_samples = sample_rate * 60 // tempo # fade out last note\n", " fade_out = np.linspace(1., 0., n_fade_out_samples)**2\n", " merged[-n_fade_out_samples:] *= fade_out\n", " return merged\n", "\n", "def play_chords(chords, tempo=160, amplitude=0.1, sample_rate=44100, filepath=None):\n", " '''\n", " Reads chords (sets of 4 notes) in a chorale (list of chords) \n", " and outputs an audio file that can be played.\n", " \n", " Arguments:\n", " chords: A list of chords, for instance a full chorale\n", " Optional arguments:\n", " tempo: The tempo of the music\n", " amplitude: The amplitude of the sine waves to be played\n", " sample_rate: How many frequencies are sampled ~ music quality\n", " '''\n", " samples = amplitude * chords_to_samples(chords, tempo, sample_rate)\n", " if filepath:\n", " from scipy.io import wavfile\n", " samples = (2**15 * samples).astype(np.int16)\n", " wavfile.write(filepath, sample_rate, samples)\n", " return display(Audio(filepath))\n", " else:\n", " return display(Audio(samples, rate=sample_rate))" ] }, { "cell_type": "markdown", "metadata": { "id": "eLMqDcHfOuIN" }, "source": [ "## Part II: Preliminary Data Analysis and Preprocessing" ] }, { "cell_type": "markdown", "metadata": { "id": "P-zJjNinOxch" }, "source": [ "The dataset is composed of 382 chorales composed by Johann Sebastian Bach. Each chorale is 100 to 640 time steps long, and each time step contains 4 integers, where each integer corresponds to a note's index on a piano (except for the value 0, which means that no note is played). \n", "\n", "Our goal is to train a model—recurrent, convolutional, or both—that can predict the next time step (four notes), given a sequence of time steps from a chorale. Once trained, we can use this model to generate Bach-like music, one note at a time. We can do this by giving the model the start of a chorale and asking it to predict the next time step, then appending these time steps to the input sequence and asking the model for the next note, and so on. " ] }, { "cell_type": "markdown", "metadata": { "id": "krWYHPmx4WIM" }, "source": [ "### **Q1) Check that notes range from `min_note = 36` (which is C1, i.e. C/Do on octave 1) to `max_note = 81` (which is A5, i.e. A/La on octave 5), including `0` for silences. Calculate the total number of notes `n_notes`.**" ] }, { "cell_type": "markdown", "metadata": { "id": "Gmg9q2tv6SKM" }, "source": [ "First, explore the dataset:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "TgnGCmyt7Vv6" }, "outputs": [], "source": [ "# Explore the dataset: How is it structured? What does a sample look like? etc." ] }, { "cell_type": "markdown", "metadata": { "id": "mt_1hlL87drp" }, "source": [ "Second, let's group all of the chorales' notes in a set called `notes`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "2kZ-AMcpAdVg" }, "outputs": [], "source": [ "notes = set() # Initialize the notes with an empty set\n", "for chorales in (_____, _____, _____): # Loop through chorales in training/validation/test sets\n", " for chorale in _____: # Loop through all chorales\n", " for chord in _____: # Loop through chords within a chorale \n", " notes |= set(chord) # Add notes that are in chord but not yet in notes" ] }, { "cell_type": "markdown", "metadata": { "id": "N9_5Nu3I6xJi" }, "source": [ "Third, calculate `min_note` and `max_note`.\n", "\n", "Hint: Be careful to exclude 0 when calculating `min_note`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "pCVmvNAz6WVF" }, "outputs": [], "source": [ "min_note = __________\n", "max_note = __________" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "Ly1Jh-ku5igN" }, "outputs": [], "source": [ "# This will return an error message if your code is erroneous\n", "assert min_note == 36\n", "assert max_note == 81" ] }, { "cell_type": "markdown", "metadata": { "id": "vltWq4fdk69F" }, "source": [ "Finally, calculate the total number of notes `n_notes`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "6g64vvrelA-4" }, "outputs": [], "source": [ "# Write your code below" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "TeLbN19zlDEc" }, "outputs": [], "source": [ "# This will return an error message if your code is erroneous\n", "assert n_notes == 47" ] }, { "cell_type": "markdown", "metadata": { "id": "bAvF17_G_Rhb" }, "source": [ "### **Q2) What is the training/validation/test split?**\n", "\n", "Hint: You may use the [`len`](https://docs.python.org/3/library/functions.html#len) build-in function to get the length of a list" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "YhH1T8pe_jjZ" }, "outputs": [], "source": [ "# Calculate the number of chorales in each of the training/validation/test sets" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "Y70tAM1r_FOq" }, "outputs": [], "source": [ "# What is the training/validation/test split (in %)?" ] }, { "cell_type": "markdown", "metadata": { "id": "lakqnDVyAdVh" }, "source": [ "### **Q3) Listen to a few chorales 🎵**\n", "\n", "Hint 1: Use the `play_chords` function defined above. Type `play_chords?` to display its documentation.\n", "\n", "Hint 2: You can start by selecting chorales from the training set `train_chorales`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "YuujH-JT8BO7" }, "outputs": [], "source": [ "# Explore `train_chorales` and `play_chords` to get some intuition" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "YODP8PyLAdVi" }, "outputs": [], "source": [ "# Use `play_chords` to produce chorales you can listen to" ] }, { "cell_type": "markdown", "metadata": { "id": "uwUt5MVWAdVi" }, "source": [ "Divine! 🎶" ] }, { "cell_type": "markdown", "metadata": { "id": "I0c8YNDSAdVi" }, "source": [ "In order to be able to generate new chorales, we want to train a model that can predict the next chord given all the previous chords. If we naively try to predict the next chord in one shot, predicting all 4 notes at once, we run the risk of getting notes that don't go very well together (believe Géron, he tried). It's much better and simpler to predict one note at a time. \n", "\n", "So we will need to preprocess every chorale, turning each chord into an arpegio (i.e., a sequence of notes rather than notes played simultaneously). Each chorale will be a long sequence of notes (rather than chords), and we can just train a model that can predict the next note given all the previous notes. We will use a sequence-to-sequence approach, where we feed a window to the neural net, and it tries to predict that same window shifted one time step into the future.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "jJ1riBCLAdVi" }, "outputs": [], "source": [ "def create_target(batch):\n", " X = batch[:, :-1]\n", " Y = batch[:, 1:] # predict next note in each arpegio, at each step\n", " return X, Y" ] }, { "cell_type": "markdown", "metadata": { "id": "uuqfxD3lCrq_" }, "source": [ "We will also shift the values so that they range from 0 to 46, where 0 represents silence, and values 1 to 46 represent notes 36 (C1) to 81 (A5)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "6Wx4mGrfCv85" }, "outputs": [], "source": [ "def preprocess(window):\n", " window = tf.where(window == 0, window, window - min_note + 1) # shift values\n", " return tf.reshape(window, [-1]) # convert to arpegio" ] }, { "cell_type": "markdown", "metadata": { "id": "NH43cA-yCVIL" }, "source": [ "And we will train the model on windows of 128 notes (i.e., 32 chords).\n", "\n", "Since the dataset fits in memory, we could preprocess the chorales in RAM using any Python code we like, but I will demonstrate here how to do all the preprocessing using `tf.data` (see Géron Ch16 more details about creating windows using `tf.data`)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "IIClQTBNCacY" }, "outputs": [], "source": [ "def bach_dataset(chorales, batch_size=32, shuffle_buffer_size=None,\n", " window_size=32, window_shift=16, cache=True):\n", " def batch_window(window):\n", " return window.batch(window_size + 1)\n", "\n", " def to_windows(chorale):\n", " dataset = tf.data.Dataset.from_tensor_slices(chorale)\n", " dataset = dataset.window(window_size + 1, window_shift, drop_remainder=True)\n", " return dataset.flat_map(batch_window)\n", "\n", " chorales = tf.ragged.constant(chorales, ragged_rank=1)\n", " dataset = tf.data.Dataset.from_tensor_slices(chorales)\n", " dataset = dataset.flat_map(to_windows).map(preprocess)\n", " if cache:\n", " dataset = dataset.cache()\n", " if shuffle_buffer_size:\n", " dataset = dataset.shuffle(shuffle_buffer_size)\n", " dataset = dataset.batch(batch_size)\n", " dataset = dataset.map(create_target)\n", " return dataset.prefetch(1)" ] }, { "cell_type": "markdown", "metadata": { "id": "7KJd4y3moPW3" }, "source": [ "Note that this `bach_dataset` function is designed to output the sequence using the shape `(batch_size,number_of_chords)` because the sequence is then fed into an [`Embedding`](https://keras.io/api/layers/core_layers/embedding/) layer. It would need to output the sequence using the shape `(batch_size,number_of_chords,1)` to be directly fed into an [LSTM layer](https://keras.io/api/layers/recurrent_layers/lstm/)." ] }, { "cell_type": "markdown", "metadata": { "id": "coB_lFeXC9ak" }, "source": [ "### **Q4) Use the function `bach_dataset` above to create the training, validation, and test sets. Use a `shuffle_buffer_size` of `1000` for the training set.**" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "cBt_-SJBAdVk" }, "outputs": [], "source": [ "train_set = _________(_________, __________=_____)\n", "valid_set = _________(_________)\n", "test_set = _________(_________)" ] }, { "cell_type": "markdown", "metadata": { "id": "pCi9SOD3Dvzi" }, "source": [ "## Part III: Training a small [WaveNet](https://www.deepmind.com/blog/wavenet-a-generative-model-for-raw-audio) model and generating your first chorale" ] }, { "cell_type": "markdown", "metadata": { "id": "-TiGmzoWtFxg" }, "source": [ "### **Q5) Implement a small [WaveNet](https://www.deepmind.com/blog/wavenet-a-generative-model-for-raw-audio) model to process the sequence of chords**" ] }, { "cell_type": "markdown", "metadata": { "id": "A3QcHiG_t7QP" }, "source": [ "We could feed the note values directly to the model, as floats, but this would probably not give good results. Indeed, the relationships between notes are not that simple: for example, if you replace a C3 with a C4, the melody will still sound fine, even though these notes are 12 semi-tones apart (i.e., one octave). Conversely, if you replace a C3 with a C\\#3, it's very likely that the chord will sound horrible, despite these notes being just next to each other. So we will use an `Embedding` layer to convert each note to a small vector representation (see Géron Chapter 16 for more details on embeddings). We will use 5-dimensional embeddings, so the output of this first layer will have a shape of `[batch_size, window_size, n_embedding_dims=5]`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "ZHGQqo7CtrXn" }, "outputs": [], "source": [ "# Choose the number of embedding dimensions here. Géron recommends 5.\n", "n_embedding_dims = ______" ] }, { "cell_type": "markdown", "metadata": { "id": "NqrAKXlGuisg" }, "source": [ "Now implement a small [WaveNet](https://www.deepmind.com/blog/wavenet-a-generative-model-for-raw-audio) (we recommend starting with no more than 5 layers).\n", "\n", "Hint 1: You need to start with an embedding layer to convert integer notes into a vector of length `n_embedding_dims`. For that purpose, the syntax is: `keras.layers.Embedding(input_dim=input_dim, output_dim=output_dim,input_shape=[None])`. `input_dim` is the number of possible integer categories of the notes we would like to convert, while `output_dim` is the number of embedding dimensions.\n", "\n", "Hint 2: A [WaveNet](https://www.deepmind.com/blog/wavenet-a-generative-model-for-raw-audio) is a sequence of [Conv1D](https://keras.io/api/layers/convolution_layers/convolution1d/) layers with increased dilation rate. For instance, below is a WaveNet with 3 layers and a constant number of filters equal to 128 (increase the filter size for more representation power). Note the increase in the dilation rate. \n", "```\n", "keras.layers.Conv1D(filters=128, kernel_size=2, padding=\"causal\", activation=\"relu\", dilation_rate=2),\n", "keras.layers.Conv1D(filters=128, kernel_size=2, padding=\"causal\", activation=\"relu\", dilation_rate=4),\n", "keras.layers.Conv1D(filters=128, kernel_size=2, padding=\"causal\", activation=\"relu\", dilation_rate=8),\n", "```\n", "\n", "Hint 3: For the final layer, you need to output the probability of the note belonging to each one of the `n_notes`. Because the probabilities need to sum to 1, we have to use a [`softmax`](https://keras.io/api/layers/activations/) activation function, used as the `activation` argument of the [`keras.layers.Dense`](https://keras.io/api/layers/activations/) layer." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "qP87koqCuJt_" }, "outputs": [], "source": [ "# We use the sequential API below but you may use the functional API instead\n", "model = keras.models.Sequential([\n", " keras.layers.Embedding(input_dim=______, output_dim=______,\n", " input_shape=[None]),\n", " __________________________________________,\n", " __________________________________________,\n", " keras.layers.Dense(________, activation=__________)\n", "])" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "qAQcAQdnFbR9" }, "outputs": [], "source": [ "# Check that your model looks right\n", "model.summary()" ] }, { "cell_type": "markdown", "metadata": { "id": "5Of7la1hypWb" }, "source": [ "### **Q6) Compile your model using [\"sparse_categorical_crossentropy\"](https://www.tensorflow.org/api_docs/python/tf/keras/losses/SparseCategoricalCrossentropy) as the loss since your outputs are not one-hot encoded, and \"accuracy\" as an additional metric to monitor during training.**\n", "\n", "Hint: Potential Keras optimizers are listed [at this link](https://keras.io/api/optimizers/)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "XBb0UeBL0uR-" }, "outputs": [], "source": [ "# Choose your optimizer\n", "optimizer = keras.optimizers._______________________" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "DD0-HeS200ln" }, "outputs": [], "source": [ "# Compile your model\n", "model.compile(loss=____________, optimizer=__________,\n", " metrics=[_______ ])" ] }, { "cell_type": "markdown", "metadata": { "id": "LnS3Py23HFWx" }, "source": [ "### **Q7) Train your model on the training set and plot the learning curves. Is your model overfitting?**\n", "\n", "Hint 1: You may use 20 epochs for training and a patience of 20 epochs for your early stopping callback.\n", "\n", "Hint 2: To plot your learning curves with [Tensorboard](https://www.tensorflow.org/tensorboard), fill out the information in the cell below" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "leX_NPGZIEEx" }, "outputs": [], "source": [ "#Change this number and rerun this cell whenever you want to change runs\n", "run_index = ___ # it should be an integer, e.g. 1\n", "\n", "run_logdir = os.path.join(os.curdir, \"my_bach_logs\", \"run_{:03d}\".format(run_index))\n", "\n", "print(run_logdir)" ] }, { "cell_type": "markdown", "metadata": { "id": "a11RV36VIugF" }, "source": [ "Define your [callbacks](https://keras.io/api/callbacks/) below. For the checkpoint `checkpoint_cb`, we recommend monitoring the validation loss to avoid overfitting. Look for \"monitor\" in the `model_checkpoint`'s documentation [at this link](https://keras.io/api/callbacks/model_checkpoint/)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "RwgGwyOiILas" }, "outputs": [], "source": [ "early_stopping_cb = tf.keras.callbacks.EarlyStopping(patience=_____)\n", "checkpoint_cb = tf.keras.callbacks.ModelCheckpoint(\"my_bach_model.h5\", \n", " save_best_only=True,\n", " monitor=_______)\n", "tensorboard_cb = tf.keras.callbacks.TensorBoard(run_logdir)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "HJojibqtISEU" }, "outputs": [], "source": [ "history = model.fit(____, # training data\n", " epochs=___, #epochs\n", " validation_data=____, # validation data\n", " callbacks=[checkpoint_cb, early_stopping_cb, tensorboard_cb])" ] }, { "cell_type": "markdown", "metadata": { "id": "soiApJl9JW4r" }, "source": [ "Visualize your learning curves using [Tensorboard](https://www.tensorflow.org/tensorboard):" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "dyVY8FYZJAxs" }, "outputs": [], "source": [ "%tensorboard --logdir=./my_bach_logs --port=8888 # Pick any 4 digits for the port" ] }, { "cell_type": "markdown", "metadata": { "id": "9ZJYztSHKX-c" }, "source": [ "### **Q8) To double check whether your model is overfitting, evaluate it on the test set using the built-in [evaluate](https://www.tensorflow.org/api_docs/python/tf/keras/Model#evaluate) method.**" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "85OUuqmsKmp8" }, "outputs": [], "source": [ "model.______(_________) # Evaluate the model on the test set" ] }, { "cell_type": "markdown", "metadata": { "id": "J025prJpNCDh" }, "source": [ "Ideally, you should reach an accuracy of at least 40%. If you don't, you may:\n", "\n", "* Increase the number of trainable parameters in your model, e.g. by increasing the filter size, \n", "* Train your model for more epochs, or \n", "* Adjust your checkpoint, e.g. to monitor your validation loss ('val_loss') to avoid overfitting." ] }, { "cell_type": "markdown", "metadata": { "id": "AMUltDfuLR8Q" }, "source": [ "Now let's write a function that will generate a new chorale. We will give it a few seed chords, it will convert them to arpegios (the format expected by the model), and use the model to predict the next note, then the next, and so on. In the end, it will group the notes 4 by 4 to create chords again, and return the resulting chorale." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "P0rr0ILoLxUz" }, "outputs": [], "source": [ "def generate_chorale(model, seed_chords, length):\n", " arpegio = preprocess(tf.constant(seed_chords, dtype=tf.int64))\n", " arpegio = tf.reshape(arpegio, [1, -1])\n", " for chord in range(length):\n", " for note in range(4):\n", " #next_note = model.predict_classes(arpegio)[:1, -1:]\n", " next_note = np.argmax(model.predict(arpegio), axis=-1)[:1, -1:]\n", " arpegio = tf.concat([arpegio, next_note], axis=1)\n", " arpegio = tf.where(arpegio == 0, arpegio, arpegio + min_note - 1)\n", " return tf.reshape(arpegio, shape=[-1, 4])" ] }, { "cell_type": "markdown", "metadata": { "id": "0gZ7GKs5LUfo" }, "source": [ "### **Q9) Using seed chords from the test set, generate your first chorale! 🎼**" ] }, { "cell_type": "markdown", "metadata": { "id": "Eat6qKRuODZ3" }, "source": [ "Extract some `seed_chords` from the test set `test_chorales`.\n", "\n", "Hint: You can simply use the first 5-10 chords of one of the test chorales." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "fPJIaPVsOY9K" }, "outputs": [], "source": [ "seed_chords = ________[_____][____:______]" ] }, { "cell_type": "markdown", "metadata": { "id": "FEuAEnSbOkL1" }, "source": [ "and play them 😃\n", "\n", "Hint: You may use the function `play_chords` [defined above](#play_chords)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "mx5X2dQwO3kZ" }, "outputs": [], "source": [ "# Play the seed chords" ] }, { "cell_type": "markdown", "metadata": { "id": "kRXQa-IsRIv7" }, "source": [ "Now we are ready to generate our first chorale! Let's ask the function to generate `n_generated` more chords:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "hGxg44CXRXLz" }, "outputs": [], "source": [ "n_generated = ____________ # Choose a number of chords to generate (e.g., 20-100)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "7JrWfkXcRlZZ" }, "outputs": [], "source": [ "n_generated = 50" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "6Hbqj0pbRh1Q" }, "outputs": [], "source": [ "new_chorale = generate_chorale(model, seed_chords, n_generated)\n", "play_chords(new_chorale)" ] }, { "cell_type": "markdown", "metadata": { "id": "cmsT-25PODs_" }, "source": [ "From Géron:\n", "\n", "\"*This approach has one major flaw: it is often too conservative. Indeed, the model will not take any risk, it will always choose the note with the highest score, and since repeating the previous note generally sounds good enough, it's the least risky option, so the algorithm will tend to make notes last longer and longer. Pretty boring. Plus, if you run the model multiple times, it will always generate the same melody.*\n", "\n", "*So let's spice things up a bit! Instead of always picking the note with the highest score, we will pick the next note randomly, according to the predicted probabilities. For example, if the model predicts a C3 with 75% probability, and a G3 with a 25% probability, then we will pick one of these two notes randomly, with these probabilities. We will also add a `temperature` parameter that will control how \"hot\" (i.e., daring) we want the system to feel. A high temperature will bring the predicted probabilities closer together, reducing the probability of the likely notes and increasing the probability of the unlikely ones.*\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "DgckBx4mODs_" }, "outputs": [], "source": [ "def generate_chorale_v2(model, seed_chords, length, temperature=1):\n", " arpegio = preprocess(tf.constant(seed_chords, dtype=tf.int64))\n", " arpegio = tf.reshape(arpegio, [1, -1])\n", " for chord in range(length):\n", " for note in range(4):\n", " next_note_probas = model.predict(arpegio)[0, -1:]\n", " rescaled_logits = tf.math.log(next_note_probas) / temperature\n", " next_note = tf.random.categorical(rescaled_logits, num_samples=1)\n", " arpegio = tf.concat([arpegio, next_note], axis=1)\n", " arpegio = tf.where(arpegio == 0, arpegio, arpegio + min_note - 1)\n", " return tf.reshape(arpegio, shape=[-1, 4])" ] }, { "cell_type": "markdown", "metadata": { "id": "fA35AL5yODs_" }, "source": [ "### **Q10) Using the function `generate_chorale_v2`, generate 3 chorales using this new function: one cold (`temperature<1`), one medium (`temperature=1`), and one hot (`temperature>1`).**\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "MG9RfJPsODs_", "scrolled": true }, "outputs": [], "source": [ "new_chorale_v2_cold = generate_chorale_v2(____,____,____,____)\n", "play_chords(new_chorale_v2_cold, filepath=\"bach_cold.wav\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "SSIS_EVUODs_" }, "outputs": [], "source": [ "new_chorale_v2_medium = generate_chorale_v2(____,____,____,____)\n", "play_chords(new_chorale_v2_medium, filepath=\"bach_medium.wav\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "-muViLabODs_" }, "outputs": [], "source": [ "new_chorale_v2_hot = generate_chorale_v2(____,____,____,____)\n", "play_chords(new_chorale_v2_hot, filepath=\"bach_hot.wav\")" ] }, { "cell_type": "markdown", "metadata": { "id": "7oBoc8PnSiMG" }, "source": [ "## Part IV: Generating a Masterpiece Using Recurrent Neural Networks" ] }, { "cell_type": "markdown", "metadata": { "id": "oUP174DWSw6U" }, "source": [ "### **Q11) Improve your model's accuracy by adding batch normalization and at least one recurrent neural network layer at the end of your model.**\n", "\n", "Hint 1: Consider adding a [Long Short-Term Memory](https://keras.io/api/layers/recurrent_layers/lstm/), a [Gated Recurrent Unit](https://keras.io/api/layers/recurrent_layers/gru/), or an [Attention](https://keras.io/api/layers/attention_layers/attention/) layer.\n", "\n", "Hint 2: Batch normalization layers are documented [at this link](https://keras.io/api/layers/normalization_layers/batch_normalization/), and you may insert them between any layers to accelerate convergence during training.\n", "\n", "Hint 3: You may reuse some of the code you wrote for Q5-Q8.\n", "\n", "Hint 4: If you would like to be more systematic about your model architecture choices, you can optimize hyperparameters of your model, such as the number of filters, the layer parameters, the learning rate, the optimizer, etc. using hyperparameter optimization libraries such as the [KerasTuner](https://keras.io/keras_tuner/)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "hibDwZdBUBCz" }, "outputs": [], "source": [ "# Redesign your model's architecture" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "dAJAHSahUExB" }, "outputs": [], "source": [ "# Compile your model" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "KXa2-wbpUI9J" }, "outputs": [], "source": [ "# Define callbacks (they can really improve the accuracy if well-chosen!)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "gvnr9IPBURE2" }, "outputs": [], "source": [ "# Train your model" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "70C2H5-TUfF4" }, "outputs": [], "source": [ "# Evaluate its accuracy on the test set" ] }, { "cell_type": "markdown", "metadata": { "id": "dWirW51_UhQv" }, "source": [ "You should be able to reach accuracy values larger than 60% at this stage 😲" ] }, { "cell_type": "markdown", "metadata": { "id": "9Lq2f9-UUrrk" }, "source": [ "### **Q12) Compose a masterpiece.**\n", "\n", "Hint 1: You may reuse some of the code you wrote for Q9 and Q10.\n", "\n", "Hint 2: Experiment with other seeds, lengths and temperatures to compose your masterpiece.\n", "\n", "From Géron:\n", "**Please share your most beautiful generated chorale with me on Twitter @aureliengeron, I would really appreciate it! :))**" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "KR21u4LRV4gg" }, "outputs": [], "source": [ "# Choose and play the seed chords" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "ZL_ETZeIV7k7" }, "outputs": [], "source": [ "# Generate a new chorale that's even more beautiful than the previous one" ] }, { "cell_type": "markdown", "metadata": { "id": "9r0feOv_ODs_" }, "source": [ "You can try a fun social experiment: send your friends a few of your favorite generated chorales, plus the real chorale, and ask them to guess which one is the real one!" ] }, { "cell_type": "markdown", "metadata": { "id": "R4gLDpKSODs_" }, "source": [ "Check out [Google's Coconet model](https://homl.info/coconet), which was used for a nice [Google doodle about Bach](https://www.google.com/doodles/celebrating-johann-sebastian-bach)." ] } ], "metadata": { "accelerator": "GPU", "colab": { "include_colab_link": true, "name": "S6_1_Composing_Music_With_RNNs_CNNs.ipynb", "provenance": [], "toc_visible": true }, "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "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.9.7" }, "nav_menu": {}, "toc": { "navigate_menu": true, "number_sections": true, "sideBar": true, "threshold": 6, "toc_cell": false, "toc_section_display": "block", "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 1 }