{ "metadata": { "name": "", "signature": "sha256:724c28d3c1741d1b52fe16e574ba828b839748539631e6eb5aefc5ef55b880a3" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "Now, it's time to do some deep learning. Recall that a RBM (Restricted Boltzmann Machine) takes in a binary vector, and you can use it in the SKLearn Pipeline with a classifier. You'll want to read in Oscar's original data as an array of bitwise note vectors, and from there build the RBM to predict chords (the y's, perhaps build the chord bank and assign a unique number to each). After that, given a note vector (maybe plural?), you should be able to predict the chords for a note (notes?).\n", "\n", "This is for Oscar's musical data. The next step is to do the classification for your n-gram model." ] }, { "cell_type": "code", "collapsed": false, "input": [ "from collections import defaultdict\n", "from sklearn.neural_network import BernoulliRBM\n", "import pandas as pd\n", "import numpy as np\n", "import scipy.sparse\n", "import random, cPickle" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 43 }, { "cell_type": "code", "collapsed": false, "input": [ "# Extract chords into unique ids, e.g. 1, 2, 3, 4, 5\n", "allchords = defaultdict() # remember that it's a hash table\n", "with open(\"oscar2chords_extract.txt\", 'rb') as f:\n", " for ix, line in enumerate(f):\n", " items = line.split()\n", " allchords[ix] = items\n", "assert len(allchords) == len(set(allchords)) # ensure no duplicate chords" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": [ "# Read in Oscar's data.\n", "vectors = []\n", "notedata = pd.read_csv(open(\"oscar2notes.txt\", 'rb'), skiprows=2)\n", "allnotes = []\n", "for note, octave in zip(notedata[\"Note/Rest\"], notedata[\"Octave\"]):\n", " allnotes.append(\"%s%s\" % (note, octave))\n", "\n", "print \"Number of notes (# of samples for RBM): \", len(notedata)\n", "notedata.head()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Number of notes (# of samples for RBM): 1344\n" ] }, { "html": [ "
\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Note/RestOctaveLenOffset
0 B 3 0.500000 12.625
1 A 5 0.250000 15.000
2 F 4 3.125000 16.000
3 G 4 0.666667 20.625
4 F 4 1.250000 23.875
\n", "

5 rows \u00d7 4 columns

\n", "
" ], "metadata": {}, "output_type": "pyout", "prompt_number": 3, "text": [ " Note/Rest Octave Len Offset\n", "0 B 3 0.500000 12.625\n", "1 A 5 0.250000 15.000\n", "2 F 4 3.125000 16.000\n", "3 G 4 0.666667 20.625\n", "4 F 4 1.250000 23.875\n", "\n", "[5 rows x 4 columns]" ] } ], "prompt_number": 3 }, { "cell_type": "code", "collapsed": false, "input": [ "# Given a MUSIC21 note, such as C5 or D#7, convert it\n", "# into a note on the keyboard between 0 and 87 inclusive.\n", "# Don't convert it for mingus; try to use music21 note style\n", "# as much as possible for all this stuff.\n", "def quantify(note):\n", " notevals = {\n", " 'C' : 0,\n", " 'D' : 2,\n", " 'E' : 4,\n", " 'F' : 5,\n", " 'G' : 7,\n", " 'A' : 9,\n", " 'B' : 11\n", " }\n", " quantized = 0\n", " octave = int(note[-1]) - 1\n", " for i in note[:-1]:\n", " if i in notevals: quantized += notevals[i]\n", " if i == '-': quantized -= 1\n", " if i == '#': quantized += 1\n", " quantized += 12 * octave\n", " return quantized\n", "\n", "# Create bitwise note vectors for use with Restricted Boltzmann Machine.\n", "vectors = np.zeros((1, 88))\n", "for ix, note in enumerate(allnotes):\n", " vect = np.zeros((1, 88))\n", " vect[0, quantify(note)] = 1\n", " if ix == 0:\n", " vectors = vect\n", " else:\n", " vectors = np.vstack((vectors, vect))\n", "print vectors.shape" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "(1344, 88)\n" ] } ], "prompt_number": 4 }, { "cell_type": "markdown", "metadata": {}, "source": [ "See notes on what you should actually do.\n", "\n", "1. Annotate Oscar's chord data so you have a notes vector for each chord listing the notes that go well with it.\n", "2. Move onto each cluster; for each cluster, build a vector covering all of its notes.\n", "3. You need a training and a test set, so create those from Oscar's data somehow.\n", "4. Find a good classifier to use with this. It might be stacked RBMs, or it might not! Use whatever tool is best for the job.\n", "\n", "Step 1: build the vocabulary of possible notes (e.g. note vectors with # of notes >= 1) for the class labels (each chord's unique id)." ] }, { "cell_type": "code", "collapsed": false, "input": [ "# Convert mingus note back to music21 note. WORKS\n", "def unmingify(note):\n", " return note.replace('-','').replace('b','-')\n", " \n", "# Given a list of mingus notes (i.e. a chord), say ['A-2', 'A-3', 'E-3'],\n", "# return a bitwise notevector with possible notes to go along with it.\n", "# Takes a chord (i.e. a list of notes) -- not a freqdict\n", "# Idea: what if just generate notewise vector with exact same pitches? Indepedence assumption?\n", "def genChordNotes(chord):\n", " chord = [unmingify(note) for note in chord] # really important to unmingify notes.\n", " notevect = np.zeros((1, 88))\n", " \n", " # populate with initial pitches\n", " for note in chord:\n", " notevect[0, quantify(note)] = 1\n", " \n", " # add other octaves of initial pitches\n", " otheroctaves = range(3, 6)\n", " for note in chord:\n", " notebase = note[:-1]\n", " for octv in otheroctaves:\n", " put = bool(random.getrandbits(1)) # randomize other pitches\n", " if put is True:\n", " translated = \"%s%s\" % (notebase, octv)\n", " notevect[0, quantify(translated)] = 1\n", " \n", " # add other relevant notes if time. might have enough chords already\n", " \n", " # return the vector\n", " return notevect\n", "\n", "# Create initial arrays (1-40, one for each thing)\n", "x_train = np.zeros((1, 88))\n", "for chordID, chord in allchords.items():\n", " if chordID == 0:\n", " x_train = genChordNotes(chord)\n", " else:\n", " x_train = np.vstack((x_train, genChordNotes(chord)))\n", "y_train = allchords.keys()\n", "\n", "print \"Before adding random data: \", x_train.shape, len(y_train)\n", "\n", "# create more randomized data\n", "for chordID, chord in allchords.items():\n", " for j in xrange(5): \n", " x_train = np.vstack((x_train, genChordNotes(chord)))\n", " y_train.append(chordID)\n", "y_train = np.array(y_train).reshape(-1, )\n", "\n", "print \"After adding random data: \", x_train.shape, y_train.shape" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Before adding random data: (40, 88) 40\n", "After adding random data: (240, 88) (240,)\n" ] } ], "prompt_number": 37 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, it's time for some learning! Create a classifier to get a feel of what the training data is (no test) -- you want to get a deep understanding of what note vectors are associated with which class labels." ] }, { "cell_type": "code", "collapsed": false, "input": [ "from sklearn.ensemble import RandomForestClassifier\n", "rf = RandomForestClassifier()\n", "rf.fit(x_train, y_train)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 41, "text": [ "RandomForestClassifier(bootstrap=True, compute_importances=None,\n", " criterion='gini', max_depth=None, max_features='auto',\n", " min_density=None, min_samples_leaf=1, min_samples_split=2,\n", " n_estimators=10, n_jobs=1, oob_score=False, random_state=None,\n", " verbose=0)" ] } ], "prompt_number": 41 }, { "cell_type": "code", "collapsed": false, "input": [ "# save the classifier to disk for use with 6b. The N-Gram Pipeline, Part II.\n", "with open('part7clf.pkl', 'wb') as fid:\n", " cPickle.dump(rf, fid)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 44 }, { "cell_type": "code", "collapsed": false, "input": [ "# save the defaultdict (intID : chord) to disk for use with 6b. The N-Gram Pipeline, Part II.\n", "with open('part7cdict.pkl', 'wb') as fid:\n", " cPickle.dump(allchords, fid)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 46 }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] } ], "metadata": {} } ] }