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.