I'm trying to use NEAT to AI generate songs using music theory. I have the base code laid out here and I am currently planning to expand some of the features. My code is shown below, along with my config file: However, whenever I try to use my config file, it either returns a runtime error saying Missing configuration item: num_inputs, or if I try to use the default genome config, it returns Attribute Error: module 'neat' has no attribute 'DefaultGenomeConfig'. Any ideas would be amazing. Thanks so much in advance
import neat
import random
import numpy as np
import os
from midiutil import MIDIFile
config_path = "config.txt"
num_generations = 10
num_measures = 16
beats_per_measure = 4
num_tracks = 1
beat_duration = 0.25
output_file = "generated_music.mid"
def evaluate_genome(genome, config):
net = neat.nn.FeedForwardNetwork.create(genome, config)
melody = []
for _ in range(num_measures * beats_per_measure):
inputs = [random.random()]
output = net.activate(inputs)
note = int(output[0] * 127)
melody.append(note)
fitness = calculate_fitness(melody)
return fitness
def calculate_fitness(melody):
melodic_fitness = calculate_melodic_fitness(melody)
harmonic_fitness = calculate_harmonic_fitness(melody)
rhythmic_fitness = calculate_rhythmic_fitness(melody)
overall_fitness = melodic_fitness + harmonic_fitness + rhythmic_fitness
return overall_fitness
def calculate_melodic_fitness(melody):
melodic_fitness = 0.0 # Placeholder value
return melodic_fitness
def calculate_harmonic_fitness(melody):
harmonic_fitness = 0.0
return harmonic_fitness
def calculate_rhythmic_fitness(melody):
rhythmic_fitness = 0.0 # Placeholder value
return rhythmic_fitness
def run_neat():
local_dir = os.path.dirname(__file__)
config_path = os.path.join(local_dir, "config.txt")
config = neat.Config(
neat.DefaultGenome,
neat.DefaultReproduction,
neat.DefaultSpeciesSet,
neat.DefaultStagnation,
neat.DefaultGenomeConfig,
config_path,
)
population = neat.Population(config)
reporter = neat.StdOutReporter(True)
population.add_reporter(reporter)
winner = population.run(evaluate_genome, num_generations)
best_genome = winner
best_net = neat.nn.FeedForwardNetwork.create(best_genome, config)
melody = []
for _ in range(num_measures * beats_per_measure):
inputs = [random.random()]
output = best_net.activate(inputs)
note = int(output[0] * 127)
melody.append(note)
midi_file = MIDIFile(num_tracks)
track = 0
time = 0
for note in melody:
midi_file.addNote(track, 0, note, time, beat_duration, 100)
time += beat_duration
with open(output_file, "wb") as file:
midi_file.writeFile(file)
print("Generated music saved as", output_file)
run_neat()
fitness_criterion = max
fitness_threshold = 1000
pop_size = 100
reset_on_extinction = False
My configuration file:
[DefaultGenome]
# Node activation options: sigmoid, tanh, relu, softmax, identity
activation_default = sigmoid
activation_mutate_rate = 0.1
activation_options = sigmoid
# Node aggregation options: sum, product, min, max, mean
aggregation_default = sum
aggregation_mutate_rate = 0.0
aggregation_options = sum
# Node bias options: enabled, uniform, gauss
bias_init_type = gauss
bias_init_mean = 0.0
bias_init_stdev = 1.0
bias_max_value = 30.0
bias_min_value = -30.0
bias_mutate_power = 0.5
bias_mutate_rate = 0.7
bias_replace_rate = 0.1
# Connection weight options: enabled, uniform, gauss, adaptive, xavier
weight_init_type = gauss
weight_init_mean = 0.0
weight_init_stdev = 1.0
weight_max_value = 30.0
weight_min_value = -30.0
weight_mutate_power = 0.5
weight_mutate_rate = 0.8
weight_replace_rate = 0.1
[DefaultReproduction]
# Probability of asexual reproduction (without crossover)
asexual_reproduction_probability = 0.25
[DefaultSpeciesSet]
compatibility_threshold = 3.0
[DefaultStagnation]
species_fitness_func = max
max_stagnation = 20
species_elitism = 2
[DefaultGenomeConfig]
num_inputs = 1
num_outputs = 1
Move network configuration (num_inputs
, num_outputs
) to the [DefaultGenome]
section (not DefaultGenomeConig).
For example:
[NEAT]
fitness_criterion = max
fitness_threshold = 3.9
[DefaultGenome]
# network parameters
num_hidden = 0
num_inputs = 2
num_outputs = 1
Python-NEAT needs to find those parameters in the right section.
DefaultGenomeConfig is the name of the configuration class that coresponds to the DefaultGenome
section. I believe this is the source of confusion.
Thre's a decent documentation: https://neat-python.readthedocs.io/en/latest/config_file.html