Permalink
Browse files

Clean up code slightly and add readme

1 parent e33de5d commit ca008d2ca7a8cf7fd7e4cd9d68c4e68a828d8a0f @hexahedria committed Aug 3, 2015
Showing with 112 additions and 207 deletions.
  1. +10 −20 main.py
  2. +0 −30 piece_training.py
  3. +48 −0 readme.md
  4. +0 −99 scale_training.py
  5. +0 −58 setup.sh
  6. +8 −0 setup1.sh
  7. +11 −0 setup2.sh
  8. +35 −0 setup_optional.sh
View
@@ -3,28 +3,10 @@
import numpy
from midi_to_statematrix import *
-rel_modules = []
-
import multi_training
-rel_modules.append(multi_training)
import model
-rel_modules.append(model)
-
-def refresh():
- for mod in rel_modules:
- reload(mod)
-
-pcs = multi_training.loadPieces("music")
-# pickle.dump( pcs, gzip.GzipFile( "traindata.p.zip", "wb" ) )
-# pcs = pickle.load(gzip.GzipFile( "traindata.p.zip", "r"))
-
-m = model.Model([300,300],[100,50], dropout=0.5)
-
-multi_training.trainPiece(m, pcs, 10000)
-pickle.dump( m.learned_config, open( "output/final_learned_config.p", "wb" ) )
-
-def gen_adaptive(times,keep_thoughts=False,name="final"):
+def gen_adaptive(m,pcs,times,keep_thoughts=False,name="final"):
xIpt, xOpt = map(lambda x: numpy.array(x, dtype='int8'), multi_training.getPieceSegment(pcs))
all_outputs = [xOpt[0]]
if keep_thoughts:
@@ -47,12 +29,20 @@ def gen_adaptive(times,keep_thoughts=False,name="final"):
if keep_thoughts:
pickle.dump(all_thoughts, open('output/'+name+'.p','wb'))
-def fetch_train_thoughts(batches,name="trainthoughts"):
+def fetch_train_thoughts(m,pcs,batches,name="trainthoughts"):
all_thoughts = []
for i in range(batches):
ipt, opt = multi_training.getPieceBatch(pcs)
thoughts = m.update_thought_fun(ipt,opt)
all_thoughts.append((ipt,opt,thoughts))
pickle.dump(all_thoughts, open('output/'+name+'.p','wb'))
+if __name__ == '__main__':
+
+ pcs = multi_training.loadPieces("music")
+
+ m = model.Model([300,300],[100,50], dropout=0.5)
+
+ multi_training.trainPiece(m, pcs, 10000)
+ pickle.dump( m.learned_config, open( "output/final_learned_config.p", "wb" ) )
View
@@ -1,30 +0,0 @@
-import numpy
-from midi_to_statematrix import *
-from data import *
-
-batch_width = 5 # number of sequences in a batch
-batch_len = 16*4 # length of each sequence
-division_len = 16 # interval between possible start locations
-
-
-piece_output = midiToNoteStateMatrix("bach.mid")
-piece_input = noteStateMatrixToInputForm(piece_output)
-
-print "Piece has length {} -> seqs are 1/{}".format(len(piece_output), len(piece_output)/batch_len)
-
-def getPieceSegment():
- start = random.randrange(0,len(piece_output)-batch_len,division_len)
- return piece_input[start:start+batch_len], piece_output[start:start+batch_len]
-
-def getPieceBatch():
- i,o = zip(*[getSegment() for _ in range(batch_width)])
- return numpy.array(i), numpy.array(o)
-
-def trainPiece(model,epochs):
- for i in range(epochs)
- error = model.update_fun(*getPieceBatch())
- if i % 100 == 0:
- print "epoch {}, error={}".format(i,error)
- if i % 500 == 0 or (i % 100 == 0 and i < 1000):
- xIpt, xOpt = map(numpy.array, getPieceSegment())
- noteStateMatrixToMidi(numpy.concatenate((numpy.expand_dims(xOpt[0], 0), model.predict_fun(batch_len, 1, xIpt[0])), axis=0),i)
View
@@ -0,0 +1,48 @@
+# Biaxial Recurrent Neural Network for Music Composition
+
+This code implements a recurrent neural network trained to generate classical music. The model, which uses LSTM layers and draws inspiration from convolutional neural networks, learns to predict which notes will be played at each time step of a musical piece.
+
+You can read about it's design and hear examples on [this blog post](http://www.hexahedria.com/2015/08/03/composing-music-with-recurrent-neural-networks/).
+
+## Requirements
+
+This code is written in Python, and depends on having Theano and theano-lstm (which can be installed with pip) installed. The bare minimum you should need to do to get everything running, assuming you have Python, is
+```
+sudo pip install --upgrade --no-deps git+git://github.com/Theano/Theano.git
+sudo pip install numpy scipy theano-lstm
+```
+
+In addition, the included setup scripts should set up the environment exactly as it was when I trained the network on an Amazon EC2 g2.2xlarge instance with an external EBS volume. Installing it with other setups will likely be slightly different.
+
+## Using it
+
+First, you will need to obtain a large selection of midi music, preferably in 4/4 time, with notes correctly aligned to beats. These can be placed in a directory "music".
+
+To use the model, you need to first create an instance of the Model class:
+```python
+import model
+m = model.Model([300,300],[100,50], dropout=0.5)
+```
+where the numbers are the sizes of the hidden layers in the two parts of the network architecture. This will take a while, as this is where Theano will compile its optimized functions.
+
+Next, you need to load in the data:
+```python
+import multi_training
+pcs = multi_training.loadPieces("music")
+```
+
+Then, after creating an "output" directory for trained samples, you can start training:
+```python
+multi_training.trainPiece(m, pcs, 10000)
+```
+
+This will train using 10000 batches of 10 eight-measure segments at a time, and output a sampled output and the learned parameters every 500 iterations.
+
+Finally, you can generate a full composition after training is complete. The function `gen_adaptive` in main.py will generate a piece and also prevent long empty gaps by increasing note probabilities if the network stops playing for too long.
+```python
+gen_adaptive(m,pcs,10,name="composition")
+```
+
+There are also mechanisms to observe the hidden activations and memory cells of the network, but these are still a work in progress at the moment.
+
+Right now, there is no separate validation step, because my initial goal was to produce interesting music, not to assess the accuracy of this method. It does, however, print out the cost on the training set after every 100 iterations during training.
View
@@ -1,99 +0,0 @@
-import numpy
-import random
-from midi_to_statematrix import *
-from data import *
-
-def generateScaleNotes():
- scaletypes = [
- [0,2,4,5,7,9,11,12],
- [0,2,3,5,7,8,10,12],
- [0,2,3,5,7,8,11,12],
- ]
- start = random.randint(lowerBound, upperBound-13)
- return [x+start for x in random.choice(scaletypes)]
-
-def generateScaleSequence():
- notes = generateScaleNotes()
- pattern = [
- [(0,True)],
- [(0,False)],
- [(1,True)],
- [(1,False)],
- [(2,True)],
- [(2,False)],
- [(3,True)],
- [(3,False)],
- [(4,True)],
- [(4,False)],
- [(5,True)],
- [(5,False)],
- [(6,True)],
- [(6,False)],
- [(7,True)],
- [(7,False)],
-
- [(7,True)],
- [(7,False)],
- [(6,True)],
- [(6,False)],
- [(5,True)],
- [(5,False)],
- [(4,True)],
- [(4,False)],
- [(3,True)],
- [(3,False)],
- [(2,True)],
- [(2,False)],
- [(1,True)],
- [(1,False)],
- [(0,True)],
- [(0,False)],
-
- [(0,True)],
- [(2,True)],
- [(4,True)],
- [(7,True)],
- [(4,True)],
- [(2,True)],
- [(0,True)],
- [(0,False)],
-
- [],
- [],
- [(0,True),(2,True),(4,True)],
- [],
- [(0,True),(2,True),(4,True)],
- [(0,False),(2,False),(4,False)],
- ]
- sequence = [[(notes[note], artic) for note, artic in step] for step in pattern]
- return sequence
-
-def sequenceToNoteStateMatrix(seq):
- statematrix = []
- span = upperBound-lowerBound
- for noteset in seq:
- state = [[0,0] for x in range(span)]
- for note, artic in noteset:
- state[note-lowerBound] = [1, int(artic)]
- statematrix.append(state)
- return statematrix
-
-def trainScales(model,epochs):
- def getOpt():
- return sequenceToNoteStateMatrix(generateScaleSequence())
- def getIpt(opt):
- return noteStateMatrixToInputForm(opt)
- def getBatchIO(num):
- outs = [getOpt() for _ in range(num)]
- ins = [getIpt(out) for out in outs]
- return numpy.array(ins), numpy.array(outs)
-
- for i in range(epochs):
- error = model.update_fun(*getBatchIO(10))
- if i % 100 == 0:
- print "epoch {}, error={}".format(i,error)
- if i % 500 == 0 or (i % 100 == 0 and i < 1000):
- xOpt = getOpt()
- xIpt = getIpt(xOpt)
- noteStateMatrixToMidi(numpy.concatenate((numpy.expand_dims(xOpt[0], 0), model.predict_fun(40, 1, xIpt[0])), axis=0),i)
- i += 1
View
@@ -1,58 +0,0 @@
-sudo apt-get install -y gcc g++ gfortran build-essential git wget linux-image-generic libopenblas-dev python-dev python-pip python-nose python-numpy python-scipy htop reptyr
-sudo pip install --upgrade --no-deps git+git://github.com/Theano/Theano.git
-sudo wget http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1404/x86_64/cuda-repo-ubuntu1404_7.0-28_amd64.deb
-sudo dpkg -i cuda-repo-ubuntu1404_7.0-28_amd64.deb
-sudo apt-get update
-sudo apt-get install -y cuda
-echo -e "\nexport PATH=/usr/local/cuda/bin:$PATH\n\nexport LD_LIBRARY_PATH=/usr/local/cuda/lib64" >> .bashrc
-sudo reboot
-
-sudo apt-get update
-sudo apt-get -y dist-upgrade
-
-screen -S “theano”
-cuda-install-samples-7.0.sh ~/
-cd NVIDIA_CUDA-7.0_Samples/
-cd 1_Utilities/deviceQuery
-make
-./deviceQuery
-
-cd /usr/bin/
-sudo wget https://raw.githubusercontent.com/aurora/rmate/master/rmate
-sudo chmod 775 rmate
-
-# Mount new EBS volume (at sdf -> xvdf)
-sudo fdisk /dev/xvdf
-# Parameters:
-# n
-# p
-# 1
-#
-#
-# t
-# 1
-# 83
-# w
-sudo mkfs.ext3 -b 4096 /dev/xvdf
-
-cd ~
-mkdir external
-sudo mount -t ext3 /dev/xvdf external/
-sudo chmod 755 external
-sudo chown ubuntu external
-sudo chgrp ubuntu external
-cd external
-mkdir neural_music # and then get all files. Or maybe use git?
-
-sudo dd if=/dev/zero of=~/external/swapfile1 bs=1024 count=4194304
-sudo chown root:root ~/external/swapfile1
-sudo chmod 0600 ~/external/swapfile1
-sudo mkswap ~/external/swapfile1
-sudo swapon ~/external/swapfile1
-
-echo -e "\n[global]\nfloatX=float32\ndevice=gpu\nbase_compiledir=~/external/.theano/\nallow_gc=False\nwarn_float64=warn\n[mode]=FAST_RUN\n\n[nvcc]\nfastmath=True\n\n[cuda]\nroot=/usr/local/cuda\n" >> ~/.theanorc
-
-sudo pip install theano-lstm
-
-cd ~/external/neural_music
-python
View
@@ -0,0 +1,8 @@
+sudo apt-get install -y gcc g++ gfortran build-essential git wget linux-image-generic libopenblas-dev python-dev python-pip python-nose python-numpy python-scipy
+sudo pip install --upgrade --no-deps git+git://github.com/Theano/Theano.git
+sudo wget http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1404/x86_64/cuda-repo-ubuntu1404_7.0-28_amd64.deb
+sudo dpkg -i cuda-repo-ubuntu1404_7.0-28_amd64.deb
+sudo apt-get update
+sudo apt-get install -y cuda
+echo -e "\nexport PATH=/usr/local/cuda/bin:$PATH\n\nexport LD_LIBRARY_PATH=/usr/local/cuda/lib64" >> .bashrc
+sudo reboot
@BrainStone
BrainStone Dec 4, 2016

Never ever reboot a system without making sure the user knows about it!

View
@@ -0,0 +1,11 @@
+sudo apt-get update
+sudo apt-get -y dist-upgrade
+
+cuda-install-samples-7.0.sh ~/
+cd NVIDIA_CUDA-7.0_Samples/
+cd 1_Utilities/deviceQuery
+make
+./deviceQuery
+
+echo -e "\n[global]\nfloatX=float32\ndevice=gpu\nbase_compiledir=~/external/.theano/\nallow_gc=False\nwarn_float64=warn\n[mode]=FAST_RUN\n\n[nvcc]\nfastmath=True\n\n[cuda]\nroot=/usr/local/cuda\n" >> ~/.theanorc
+sudo pip install theano-lstm
View
@@ -0,0 +1,35 @@
+
+sudo apt-get install htop reptyr
+
+cd /usr/bin/
+sudo wget https://raw.githubusercontent.com/aurora/rmate/master/rmate
+sudo chmod 775 rmate
+
+# Mount new EBS volume (at sdf -> xvdf)
+sudo fdisk /dev/xvdf
+# Parameters:
+# n
+# p
+# 1
+#
+#
+# t
+# 1
+# 83
+# w
+sudo mkfs.ext3 -b 4096 /dev/xvdf
+
+cd ~
+mkdir external
+sudo mount -t ext3 /dev/xvdf external/
+sudo chmod 755 external
+sudo chown ubuntu external
+sudo chgrp ubuntu external
+cd external
+mkdir neural_music # and then get all files. Or maybe use git?
+
+sudo dd if=/dev/zero of=~/external/swapfile1 bs=1024 count=4194304
+sudo chown root:root ~/external/swapfile1
+sudo chmod 0600 ~/external/swapfile1
+sudo mkswap ~/external/swapfile1
+sudo swapon ~/external/swapfile1

0 comments on commit ca008d2

Please sign in to comment.