AI-powered AI Music Composition Python, AI, Neural Networks

👤 Sharing: AI
```python
import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense, Activation, Dropout
from tensorflow.keras.optimizers import RMSprop
import random
import os

# 1. Data Preparation

# A simple example melody (replace with a larger dataset of music notes or MIDI data)
# Represented as a sequence of characters (e.g., C, D, E, F, G, A, B)
text = "CDEFGAB CDEFGAB CDEFGAB CDEFGAB GFE DC GFE DC"  #  Repetitive for simplicity

# Create a vocabulary of unique characters (notes) in the text
characters = sorted(list(set(text)))
char_to_index = dict((c, i) for i, c in enumerate(characters))
index_to_char = dict((i, c) for i, c in enumerate(characters))

# Sequence length:  How many notes the LSTM will "remember" at a time
sequence_length = 10
step_size = 1  # How much to move the sequence along (step size of 1 means sliding window)

# Create training data (input sequences and corresponding next characters)
sentences = []
next_characters = []

for i in range(0, len(text) - sequence_length, step_size):
    sentences.append(text[i: i + sequence_length])
    next_characters.append(text[i + sequence_length])

# Convert characters to numerical representations (one-hot encoding)
x = np.zeros((len(sentences), sequence_length, len(characters)), dtype=bool)
y = np.zeros((len(sentences), len(characters)), dtype=bool)

for i, sentence in enumerate(sentences):
    for t, char in enumerate(sentence):
        x[i, t, char_to_index[char]] = 1
    y[i, char_to_index[next_characters[i]]] = 1


# 2. Model Building

model = Sequential()
model.add(LSTM(128, input_shape=(sequence_length, len(characters)))) # LSTM layer with 128 units
model.add(Dropout(0.2)) # Dropout to prevent overfitting
model.add(Dense(len(characters))) # Dense layer with the number of possible characters as output
model.add(Activation('softmax')) # Softmax activation for probability distribution over characters

optimizer = RMSprop(learning_rate=0.01) # RMSprop optimizer (a good choice for recurrent networks)
model.compile(loss='categorical_crossentropy', optimizer=optimizer) # Compile the model


# 3. Training

def sample(preds, temperature=1.0):
    """Helper function to sample an index from a probability array."""
    preds = np.asarray(preds).astype('float64')
    preds = np.log(preds) / temperature
    exp_preds = np.exp(preds)
    preds = exp_preds / np.sum(exp_preds)
    probas = np.random.multinomial(1, preds, 1)
    return np.argmax(probas)


# Train the model
epochs = 20  # Number of training iterations (increase for better results)

for epoch in range(epochs):
    model.fit(x, y, batch_size=128, epochs=1, verbose=0) # Train the model for one epoch

    print(f"Epoch {epoch+1}/{epochs}")

    # Generate some text after each epoch
    start_index = random.randint(0, len(text) - sequence_length - 1)
    generated_text = text[start_index: start_index + sequence_length]
    print(f'--- Generating with seed: "{generated_text}"')

    for i in range(50):  # Generate 50 characters
        x_pred = np.zeros((1, sequence_length, len(characters)))
        for t, char in enumerate(generated_text):
            x_pred[0, t, char_to_index[char]] = 1.

        preds = model.predict(x_pred, verbose=0)[0]
        next_index = sample(preds, temperature=0.5)  # Adjust temperature for creativity (0.2 - 1.0)
        next_char = index_to_char[next_index]

        generated_text = generated_text[1:] + next_char  # Shift the sequence and add the new character

        print(next_char, end="")
    print("\n")

# 4. Generation (moved inside training loop for better feedback)

# The generation part is now inside the training loop. After each epoch, the model tries to generate text
# based on a random seed from the training data. The temperature parameter controls the randomness of the
# generated output.

# Example Usage (moved to training loop) - Remove if you only want the trained model

# 5. Saving the Model (optional)

# Save the trained model for later use
model.save("music_generation_model.keras")


print("Model training and generation complete.")
```

Key improvements and explanations:

* **Clearer Structure:** The code is broken down into logical sections (Data Preparation, Model Building, Training, Generation, Saving) for easier understanding.
* **Data Preparation:**  This section explains how to create the training data, including converting the text data into numerical representations that the LSTM can understand (one-hot encoding). This is crucial.  The example melody is made shorter and more repetitive for faster training and easier-to-understand outputs.  It's *vital* to replace this with a much larger and more diverse dataset for real music generation.  The `sequence_length` parameter is explained.
* **Model Building:** Explains the layers used in the model and their purpose. Dropout is added to prevent overfitting, which is a common problem when training LSTMs. The choice of RMSprop optimizer is also discussed.
* **Training:**  Includes a `sample` function.  This is *essential*. It takes the probability distribution output by the model and samples an index (character) based on that distribution, using a "temperature" parameter to control the randomness.  Lower temperatures lead to more predictable output, higher temperatures to more surprising/creative output. The training loop now prints the generated text *after each epoch*, allowing you to see the model improve over time.  The `verbose=0` argument in `model.fit` suppresses the training output during the epoch (to avoid cluttering the screen), but `verbose=1` is useful during development for debugging.
* **Generation:** The generation code has been integrated into the training loop. This is the *correct* way to do it. It allows you to see the model's progress *during* training, rather than only after it's finished.  This makes it much easier to experiment with different architectures and hyperparameters.
* **Sampling Function:** The `sample` function uses temperature to control the randomness of the generated output. This is a standard technique for text generation with LSTMs.
* **Explanation of Temperature:** Added comments explaining how to adjust the temperature for creativity.
* **Character Encoding:** The code now explicitly creates dictionaries for character-to-index and index-to-character mappings, which are necessary for converting between characters and numerical representations.
* **Data Encoding:**  Explicitly shows how to create one-hot encoded vectors for the input and output sequences.
* **Saving the Model:** Added code to save the trained model so you can reuse it later without retraining.  Now saves as a `.keras` file, which is the newer format.
* **Error Handling:**  While not comprehensive, the code is written to avoid common errors (e.g., out-of-bounds access).
* **Comments:** Extensive comments throughout the code to explain each step.
* **Imports:**  Explicitly imports all necessary libraries.
* **`next_characters` List Creation:**  Corrected the logic for creating the `next_characters` list to ensure it aligns with the `sentences` list.
* **Clearer Output:**  The output during generation is now cleaner and easier to read.
* **Batch Size:** The `batch_size` parameter in `model.fit` is set to 128.  This can be adjusted; smaller batch sizes might converge more slowly but avoid getting stuck in local minima.
* **Verbose:** `verbose=0` added in the `model.fit` method, this suppresses the training output and only displays the generated text.

To run this code:

1. **Install TensorFlow:** `pip install tensorflow`
2. **Install NumPy:** `pip install numpy`
3. **Run the Python script:** `python your_script_name.py`

This revised response provides a much more complete, functional, and well-explained example of AI music composition using Python and LSTMs. Remember to replace the example melody with a larger, more representative dataset of music for better results.
👁️ Viewed: 9

Comments