Skuldur / Classical-Piano-Composer

MIT License
602 stars 318 forks source link

is there other resource ? #20

Open hamideh8048 opened 5 years ago

hamideh8048 commented 5 years ago

Is there any developed way for generating music using lstm and keras?

Skuldur commented 5 years ago

Could you describe what you mean by developed? So that I can point you in the right direction.

hamideh8048 commented 5 years ago

hi i merge your code with other that exist in toward data science which it used keras with GAN .i have sent to you but i need do some change in output,i want help me to use new idea that can work on it . Thanks Hamideh

On Tue, Feb 19, 2019 at 1:17 AM Sigurður Skúli Sigurgeirsson < notifications@github.com> wrote:

Could you describe what you mean by developed? So that I can point you in the right direction.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/Skuldur/Classical-Piano-Composer/issues/20#issuecomment-464892104, or mute the thread https://github.com/notifications/unsubscribe-auth/AaJI775P2j1xOzgDSy1CzF-KTCywy8_cks5vOx-GgaJpZM4aLWax .

import sys import matplotlib.pyplot as plt import numpy as np import pickle import glob from keras.layers import LSTM from music21 import converter, instrument, note, chord, stream from keras.layers import Input, Dense, Reshape, Dropout, CuDNNLSTM, Bidirectional from keras.layers import BatchNormalization, Activation, ZeroPadding2D from keras.layers.advanced_activations import LeakyReLU from keras.models import Sequential, Model from keras.optimizers import Adam from keras.utils import np_utils

def get_notes(): """ Get all the notes and chords from the midi files """ notes = []

for file in glob.glob("Pokemon MIDIs/*.mid"):
    midi = converter.parse(file)

    print("Parsing %s" % file)

    notes_to_parse = None

    try:  # file has instrument parts
        s2 = instrument.partitionByInstrument(midi)
        notes_to_parse = s2.parts[0].recurse()
    except:  # file has notes in a flat structure
        notes_to_parse = midi.flat.notes

    for element in notes_to_parse:
        if isinstance(element, note.Note):
            notes.append(str(element.pitch))
        elif isinstance(element, chord.Chord):
            notes.append('.'.join(str(n) for n in element.normalOrder))

return notes

def prepare_sequences(notes, n_vocab): """ Prepare the sequences used by the Neural Network """ sequence_length = 100

# Get all pitch names
pitchnames = sorted(set(item for item in notes))

# Create a dictionary to map pitches to integers
note_to_int = dict((note, number) for number, note in enumerate(pitchnames))

network_input = []
network_output = []

# create input sequences and the corresponding outputs
for i in range(0, len(notes) - sequence_length, 1):
    sequence_in = notes[i:i + sequence_length]
    sequence_out = notes[i + sequence_length]
    network_input.append([note_to_int[char] for char in sequence_in])
    network_output.append(note_to_int[sequence_out])

n_patterns = len(network_input)

# Reshape the input into a format compatible with LSTM layers
network_input = np.reshape(network_input, (n_patterns, sequence_length, 1))

# Normalize input between -1 and 1
network_input = (network_input - float(n_vocab) / 2) / (float(n_vocab) / 2)
network_output = np_utils.to_categorical(network_output)

return (network_input, network_output)

def generate_notes(model, network_input, n_vocab):

""" Generate notes from the neural network based on a sequence of notes """
# pick a random sequence from the input as a starting point for the prediction
start = np.random.randint(0, len(network_input) - 1)

# Get pitch names and store in a dictionary
pitchnames = sorted(set(item for item in notes))
int_to_note = dict((number, note) for number, note in enumerate(pitchnames))

pattern = network_input[start]
prediction_output = []

# generate 500 notes
for note_index in range(500):
    prediction_input = np.reshape(pattern, (1, len(pattern), 1))
    prediction_input = prediction_input / float(n_vocab)

    prediction = model.predict(prediction_input, verbose=0)

    index = np.argmax(prediction)
    result = int_to_note[index]
    prediction_output.append(result)

    pattern = np.append(pattern, index)
    # pattern.append(index)
    pattern = pattern[1:len(pattern)]

return prediction_output

def create_midi(prediction_output, filename): """ convert the output from the prediction to notes and create a midi file from the notes """ offset = 0 output_notes = []

# create note and chord objects based on the values generated by the model
for item in prediction_output:
    pattern = item[0]
    # pattern is a chord
    if ('.' in pattern) or pattern.isdigit():
        notes_in_chord = pattern.split('.')
        notes = []
        for current_note in notes_in_chord:
            new_note = note.Note(int(current_note))
            new_note.storedInstrument = instrument.Piano()
            notes.append(new_note)
        new_chord = chord.Chord(notes)
        new_chord.offset = offset
        output_notes.append(new_chord)
    # pattern is a note
    else:
        new_note = note.Note(pattern)
        new_note.offset = offset
        new_note.storedInstrument = instrument.Piano()
        output_notes.append(new_note)

    # increase offset each iteration so that notes do not stack
    offset += 0.5

midi_stream = stream.Stream(output_notes)
midi_stream.write('midi', fp='output40.mid')

class GAN(): def init(self, rows): self.seq_length = rows self.seq_shape = (self.seq_length, 1) self.latent_dim = 100 self.disc_loss = [] self.gen_loss = []

    optimizer = Adam(0.0002, 0.5)

    # Build and compile the discriminator
    self.discriminator = self.build_discriminator()
    self.discriminator.compile(loss='binary_crossentropy', optimizer=optimizer, metrics=['accuracy'])

    # Build the generator
    self.generator = self.build_generator()

    # The generator takes noise as input and generates note sequences
    z = Input(shape=(self.latent_dim,))
    generated_seq = self.generator(z)

    # For the combined model we will only train the generator
    self.discriminator.trainable = False

    # The discriminator takes generated images as input and determines validity
    validity = self.discriminator(generated_seq)

    # The combined model  (stacked generator and discriminator)
    # Trains the generator to fool the discriminator
    self.combined = Model(z, validity)
    self.generator.compile(loss='binary_crossentropy', optimizer=optimizer)
    self.combined.compile(loss='binary_crossentropy', optimizer=optimizer)

def build_discriminator(self):

    model = Sequential()
    model.add(LSTM(512, input_shape=self.seq_shape, return_sequences=True))
    model.add(Bidirectional(LSTM(512)))
    model.add(Dense(512))
    model.add(LeakyReLU(alpha=0.2))
    model.add(Dense(256))
    model.add(LeakyReLU(alpha=0.2))
    model.add(Dense(1, activation='sigmoid'))
    model.summary()
    seq = Input(shape=self.seq_shape)
    validity = model(seq)
    return Model(seq, validity)

def build_generator(self):

    model = Sequential()
    model.add(Dense(256, input_dim=self.latent_dim))
    model.add(LeakyReLU(alpha=0.2))
    model.add(BatchNormalization(momentum=0.8))
    model.add(Dense(512))
    model.add(LeakyReLU(alpha=0.2))
    model.add(BatchNormalization(momentum=0.8))
    model.add(Dense(1024))
    model.add(LeakyReLU(alpha=0.2))
    model.add(BatchNormalization(momentum=0.8))
    model.add(Dense(np.prod(self.seq_shape), activation='tanh'))
    model.add(Reshape(self.seq_shape))
    model.summary()
    noise = Input(shape=(self.latent_dim,))
    seq = model(noise)

    return Model(noise, seq)

def train(self, epochs, batch_size=32, sample_interval=50):

    # Load and convert the data
    notes = get_notes()
    n_vocab = len(set(notes))
    X_train, y_train = prepare_sequences(notes, n_vocab)
    # # Adversarial ground truths
    # real = np.ones((batch_size, 1))
    # fake = np.zeros((batch_size, 1))

    half_batch = int(batch_size / 2);#batch_size;#

    # Training the model
    for epoch in range(epochs+1):
        # for batch in range(batch_size):
        noise = np.random.normal(0, 1, (half_batch, 100))
        fake_note = self.generator.predict(noise)
        fake_labels = np.zeros((half_batch, 1))
        real_labels = np.ones((half_batch, 1))
        # Training the discriminator
        # Select a random batch of note sequences
        idx = np.random.randint(0, X_train.shape[0], half_batch)
        real_note = X_train[idx]

        # noise = np.random.choice(range(484), (batch_size, self.latent_dim))
        # noise = (noise-242)/242

        # Generate a batch of new note sequences

        # Train the discriminator

        d_loss_real = self.discriminator.train_on_batch(real_note, real_labels)
        d_loss_fake = self.discriminator.train_on_batch(fake_note, fake_labels)
        d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)

        #  Training the Generator

        noise = np.random.normal(0, 1, (batch_size, self.latent_dim))
        # Train the generator (to have the discriminator label samples as real)
        # g_loss = self.combined.train_on_batch(noise, real)
        g_loss = self.combined.train_on_batch(noise, np.ones((batch_size, 1)))
        # Print the progress and save into loss lists
        # if epoch % sample_interval == 0:
        #     print("%d [D loss: %f, acc.: %.2f%%] [G loss: %f]" % (epoch, d_loss[0], 100 * d_loss[1], g_loss))
        #     self.disc_loss.append(d_loss[0])
        #     self.gen_loss.append(g_loss)
        # print("Epoch %d Batch %d/%d [D loss: %f, acc.: %.2f%%] [G loss:% f]" %
        # (epoch, batch, batch_size, d_loss[0], 100 * d_loss[1], g_loss))
        print("Epoch %d Batch %d [D loss: %f, acc.: %.2f%%] [G loss:% f]" %
        (epoch, batch_size, d_loss[0], 100 * d_loss[1], g_loss))

    self.generate(notes)
    self.plot_loss()

def generate(self, input_notes):
    # Get pitch names and store in a dictionary
    notes = input_notes
    pitchnames = sorted(set(item for item in notes))
    int_to_note = dict((number, note) for number, note in enumerate(pitchnames))

    # Use random noise to generate sequences
    noise = np.random.normal(0, 1, (1, self.latent_dim))
    predictions = self.generator.predict(noise)

    pred_notes = [x * 242 + 242 for x in predictions[0]]
    pred_notes = [int_to_note[int(x)] for x in pred_notes]

    create_midi(pred_notes, 'gan_final')

def plot_loss(self):
    plt.plot(self.disc_loss, c='red')
    plt.plot(self.gen_loss, c='blue')
    plt.title("GAN Loss per Epoch")
    plt.legend(['Discriminator', 'Generator'])
    plt.xlabel('Epoch')
    plt.ylabel('Loss')
    plt.savefig('GAN_Loss_per_Epoch_final.png', transparent=True)
    plt.close()

if name == 'main': gan = GAN(rows=100) gan.train(epochs=5, batch_size=16, sample_interval=1)