New Docker Image
In the previous blog I was able to find the right version of Magenta and TensorFlow to work on my CPU. Now I'd like to save these changes as a new Docker image. It is quite simple (but not a good practice) to create a new TensorFlow Magenta 0.3.6 Docker image from a container's changes
tf@ubuntu:~$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES jolly_bardeen f0f77d90b611 tensorflow/magenta "bash" About an hour ago Up About an hour 0.0.0.0:6006->6006/tcp, 8888/tcp upbeat_poitras tf@ubuntu:~$ docker commit f0f77d90b611 tensorflow/magenta:version0.3.6 sha256:20c47039f777fab9d936b7f9c353c080c2ea02dc323b742b4d498e355f9d0f6e
Now I can start my container with the version of Magenta, which can work on my CPU.
tf@ubuntu:~$ docker run -it -p 6006:6006 -v /tmp/magenta:/magenta-data tensorflow/magenta:version0.3.6
Porting Hello Magenta Colab Notebook
I've played with Hello Magenta Colab Notebook in one of my previous blog. Now I'd like to reproduce this colab in my Docker runtime environment,
My environment is different in several ways:
- Magenta runs in a Docker container.
- There is no GPU.
- CPU doesn't supports AVX.
- TensorFlow and Magenta are at different version than in colab.
As the first step I've removed Colab specific code and generated first MIDI file (you can listen the generated music from attached file) in my container:
import magenta.music as mm import magenta import tensorflow print 'Done!' print magenta.__version__ print tensorflow.__version__ from magenta.protobuf import music_pb2 twinkle_twinkle = music_pb2.NoteSequence() # Add the notes to the sequence. twinkle_twinkle.notes.add(pitch=60, start_time=0.0, end_time=0.5, velocity=80) twinkle_twinkle.notes.add(pitch=60, start_time=0.5, end_time=1.0, velocity=80) twinkle_twinkle.notes.add(pitch=67, start_time=1.0, end_time=1.5, velocity=80) twinkle_twinkle.notes.add(pitch=67, start_time=1.5, end_time=2.0, velocity=80) twinkle_twinkle.notes.add(pitch=69, start_time=2.0, end_time=2.5, velocity=80) twinkle_twinkle.notes.add(pitch=69, start_time=2.5, end_time=3.0, velocity=80) twinkle_twinkle.notes.add(pitch=67, start_time=3.0, end_time=4.0, velocity=80) twinkle_twinkle.notes.add(pitch=65, start_time=4.0, end_time=4.5, velocity=80) twinkle_twinkle.notes.add(pitch=65, start_time=4.5, end_time=5.0, velocity=80) twinkle_twinkle.notes.add(pitch=64, start_time=5.0, end_time=5.5, velocity=80) twinkle_twinkle.notes.add(pitch=64, start_time=5.5, end_time=6.0, velocity=80) twinkle_twinkle.notes.add(pitch=62, start_time=6.0, end_time=6.5, velocity=80) twinkle_twinkle.notes.add(pitch=62, start_time=6.5, end_time=7.0, velocity=80) twinkle_twinkle.notes.add(pitch=60, start_time=7.0, end_time=8.0, velocity=80) twinkle_twinkle.total_time = 8 twinkle_twinkle.tempos.add(qpm=60); # Here's another NoteSequence! teapot = music_pb2.NoteSequence() teapot.notes.add(pitch=69, start_time=0, end_time=0.5, velocity=80) teapot.notes.add(pitch=71, start_time=0.5, end_time=1, velocity=80) teapot.notes.add(pitch=73, start_time=1, end_time=1.5, velocity=80) teapot.notes.add(pitch=74, start_time=1.5, end_time=2, velocity=80) teapot.notes.add(pitch=76, start_time=2, end_time=2.5, velocity=80) teapot.notes.add(pitch=81, start_time=3, end_time=4, velocity=80) teapot.notes.add(pitch=78, start_time=4, end_time=5, velocity=80) teapot.notes.add(pitch=81, start_time=5, end_time=6, velocity=80) teapot.notes.add(pitch=76, start_time=6, end_time=8, velocity=80) teapot.total_time = 8 teapot.tempos.add(qpm=60); drums = music_pb2.NoteSequence() drums.notes.add(pitch=36, start_time=0, end_time=0.125, is_drum=True, instrument=10, velocity=80) drums.notes.add(pitch=38, start_time=0, end_time=0.125, is_drum=True, instrument=10, velocity=80) drums.notes.add(pitch=42, start_time=0, end_time=0.125, is_drum=True, instrument=10, velocity=80) drums.notes.add(pitch=46, start_time=0, end_time=0.125, is_drum=True, instrument=10, velocity=80) drums.notes.add(pitch=42, start_time=0.25, end_time=0.375, is_drum=True, instrument=10, velocity=80) drums.notes.add(pitch=42, start_time=0.375, end_time=0.5, is_drum=True, instrument=10, velocity=80) drums.notes.add(pitch=42, start_time=0.5, end_time=0.625, is_drum=True, instrument=10, velocity=80) drums.notes.add(pitch=50, start_time=0.5, end_time=0.625, is_drum=True, instrument=10, velocity=80) drums.notes.add(pitch=36, start_time=0.75, end_time=0.875, is_drum=True, instrument=10, velocity=80) drums.notes.add(pitch=38, start_time=0.75, end_time=0.875, is_drum=True, instrument=10, velocity=80) drums.notes.add(pitch=42, start_time=0.75, end_time=0.875, is_drum=True, instrument=10, velocity=80) drums.notes.add(pitch=45, start_time=0.75, end_time=0.875, is_drum=True, instrument=10, velocity=80) drums.notes.add(pitch=36, start_time=1, end_time=1.125, is_drum=True, instrument=10, velocity=80) drums.notes.add(pitch=42, start_time=1, end_time=1.125, is_drum=True, instrument=10, velocity=80) drums.notes.add(pitch=46, start_time=1, end_time=1.125, is_drum=True, instrument=10, velocity=80) drums.notes.add(pitch=42, start_time=1.25, end_time=1.375, is_drum=True, instrument=10, velocity=80) drums.notes.add(pitch=48, start_time=1.25, end_time=1.375, is_drum=True, instrument=10, velocity=80) drums.notes.add(pitch=50, start_time=1.25, end_time=1.375, is_drum=True, instrument=10, velocity=80) drums.total_time = 1.375 drums.tempos.add(qpm=60) # This creates a file called `drums_sample_output.mid`, containing the drums solo we've been using. mm.sequence_proto_to_midi_file(drums, 'drums_sample_output.mid')
So now I have two python programs ported from Magenta Colab Notebook and generated midi output file.
tf@ubuntu:/tmp/magenta$ ls -la total 32 drwxr-xr-x 3 root root 4096 May 26 19:42 . drwxrwxrwt 10 root root 4096 May 26 19:36 .. -rw-r--r-- 1 root root 180 May 26 19:38 drums_sample_output.mid -rw-r--r-- 1 tf root 4179 May 26 19:38 hello-magenta.py -rw-r--r-- 1 tf root 4179 May 26 19:42 hello-melody-rnn.py
Where hello-melody-rnn.py contains Python code to generate new music from the model and vector of data:
import magenta.music as mm import magenta import tensorflow print 'Done!' print magenta.__version__ print tensorflow.__version__ from magenta.protobuf import music_pb2 bundle = mm.sequence_generator_bundle.read_bundle_file('/magenta-models//basic_rnn.mag') # Import dependencies. from magenta.models.melody_rnn import melody_rnn_sequence_generator from magenta.protobuf import generator_pb2 from magenta.protobuf import music_pb2 # Initialize the model. print "Initializing Melody RNN..." generator_map = melody_rnn_sequence_generator.get_generator_map() melody_rnn = generator_map['basic_rnn'](checkpoint=None, bundle=bundle) melody_rnn.initialize() print 'Done!' twinkle_twinkle = music_pb2.NoteSequence() # Add the notes to the sequence. twinkle_twinkle.notes.add(pitch=60, start_time=0.0, end_time=0.5, velocity=80) twinkle_twinkle.notes.add(pitch=60, start_time=0.5, end_time=1.0, velocity=80) twinkle_twinkle.notes.add(pitch=67, start_time=1.0, end_time=1.5, velocity=80) twinkle_twinkle.notes.add(pitch=67, start_time=1.5, end_time=2.0, velocity=80) twinkle_twinkle.notes.add(pitch=69, start_time=2.0, end_time=2.5, velocity=80) twinkle_twinkle.notes.add(pitch=69, start_time=2.5, end_time=3.0, velocity=80) twinkle_twinkle.notes.add(pitch=67, start_time=3.0, end_time=4.0, velocity=80) twinkle_twinkle.notes.add(pitch=65, start_time=4.0, end_time=4.5, velocity=80) twinkle_twinkle.notes.add(pitch=65, start_time=4.5, end_time=5.0, velocity=80) twinkle_twinkle.notes.add(pitch=64, start_time=5.0, end_time=5.5, velocity=80) twinkle_twinkle.notes.add(pitch=64, start_time=5.5, end_time=6.0, velocity=80) twinkle_twinkle.notes.add(pitch=62, start_time=6.0, end_time=6.5, velocity=80) twinkle_twinkle.notes.add(pitch=62, start_time=6.5, end_time=7.0, velocity=80) twinkle_twinkle.notes.add(pitch=60, start_time=7.0, end_time=8.0, velocity=80) twinkle_twinkle.total_time = 8 twinkle_twinkle.tempos.add(qpm=60); # Model options. Change these to get different generated sequences! input_sequence = twinkle_twinkle # change this to teapot if you want num_steps = 128 # change this for shorter or longer sequences temperature = 1.0 # the higher the temperature the more random the sequence. # Set the start time to begin on the next step after the last note ends. last_end_time = (max(n.end_time for n in input_sequence.notes) if input_sequence.notes else 0) qpm = input_sequence.tempos[0].qpm seconds_per_step = 60.0 / qpm / melody_rnn.steps_per_quarter total_seconds = num_steps * seconds_per_step generator_options = generator_pb2.GeneratorOptions() generator_options.args['temperature'].float_value = temperature generate_section = generator_options.generate_sections.add( start_time=last_end_time + seconds_per_step, end_time=total_seconds) # Ask the model to continue the sequence. sequence = melody_rnn.generate(input_sequence, generator_options) # This creates a file called `rnn_sequence_sample_output.mid`. mm.sequence_proto_to_midi_file(sequence, 'rnn_sequence_sample_output.mid')
After I run it I've got another MIDI file generated (rnn_sequence_sample_output.mid). It was generated using one (basic_rnn.mag) of provided pre-built models with Magenta Docker image.
Pre-built Magenta models:
root@2581d741336a:/magenta-data# ls -la /magenta-models total 84860 drwxr-xr-x 1 root root 4096 Aug 14 2018 . drwxr-xr-x 1 root root 4096 May 26 12:05 .. -rw------- 1 root root 20921429 Dec 15 2016 attention_rnn.mag -rw------- 1 root root 13044885 Dec 15 2016 basic_rnn.mag -rw------- 1 root root 5672564 Jan 25 2017 chord_pitches_improv.mag -rw------- 1 root root 12004379 Nov 17 2016 drum_kit_rnn.mag -rw------- 1 root root 13728925 Dec 15 2016 lookback_rnn.mag -rw------- 1 root root 6836366 Oct 31 2016 multistyle-pastiche-generator-monet -rw------- 1 root root 7118597 Oct 31 2016 multistyle-pastiche-generator-varie -rw------- 1 root root 6653887 Dec 14 2016 polyphony_rnn.mag -rw------- 1 root root 278524 Dec 16 2016 rl_rnn.mag -rw------- 1 root root 477068 Nov 7 2016 rl_tuner_note_rnn.ckpt
Generation even a simple MIDI file takes some time, memory and compute resources. So it will be important to understand this aspect to select the right integration method between RPi and Magenta.
Some questions to answer:
How much memory is consumed by Magenta to generate MIDI file? How it depends on the size of the model?
How long it takes to generate MIDI file? How it depends on the size of the model?
What is the best integration method between RPi and Magenta?
I'll try to answer these questions in my next blog.