You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python NEAT库报错AttributeError:'list'对象无'connections'属性

问题

使用Python的NEAT库做音乐生成时,运行代码触发AttributeError: 'list' object has no attribute 'connections',错误指向evaluate_genome函数里的net = neat.nn.FeedForwardNetwork.create(genome, config)行。代码结构参考官方示例,但无法完成世代迭代。

完整代码:

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,
        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()

配置文件config.txt:

[NEAT]
fitness_criterion     = max
fitness_threshold     = 400
pop_size              = 50
reset_on_extinction   = False

[DefaultStagnation]
species_fitness_func = max
max_stagnation       = 20
species_elitism      = 2

[DefaultReproduction]
elitism            = 2
survival_threshold = 0.2

[DefaultGenome]
# node activation options
activation_default      = relu
activation_mutate_rate  = 1.0
activation_options      = relu

# node aggregation options
aggregation_default     = sum
aggregation_mutate_rate = 0.0
aggregation_options     = sum

# node bias options
bias_init_mean          = 3.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

# genome compatibility options
compatibility_disjoint_coefficient = 1.0
compatibility_weight_coefficient   = 0.5

# connection add/remove rates
conn_add_prob           = 0.5
conn_delete_prob        = 0.5

# connection enable options
enabled_default         = True
enabled_mutate_rate     = 0.01

feed_forward            = True
initial_connection      = full_direct

# node add/remove rates
node_add_prob           = 0.2
node_delete_prob        = 0.2

# network parameters
num_hidden              = 1
num_inputs              = 1
num_outputs             = 1

# node response options
response_init_mean      = 1.0
response_init_stdev     = 0.0
response_max_value      = 30.0
response_min_value      = -30.0
response_mutate_power   = 0.0
response_mutate_rate    = 0.0
response_replace_rate   = 0.0

# connection weight options
weight_init_mean        = 0.0
weight_init_stdev       = 1.0
weight_max_value        = 30
weight_min_value        = -30
weight_mutate_power     = 0.5
weight_mutate_rate      = 0.8
weight_replace_rate     = 0.1

[DefaultSpeciesSet]
compatibility_threshold = 3.0
解决方案

错误根源是:population.run()默认要求评估函数接收基因组列表作为第一个参数,但你写的evaluate_genome是为单个基因组设计的,导致传入了列表而非单个Genome对象,触发connections属性不存在的错误。

有两种修复方式:

方式1:修改评估函数适配批量处理

把评估函数改成遍历基因组列表的形式,直接给每个基因组赋值适应度:

def evaluate_genomes(genomes, config):
    for genome_id, genome in genomes:
        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)
        genome.fitness = calculate_fitness(melody)

同时修改population.run()的调用:

winner = population.run(evaluate_genomes, num_generations)

方式2:改用population.evaluate()方法

如果想保留单个基因组的评估逻辑,用evaluate()替代run(),它支持传入单基因组评估函数:

# 保留原有的evaluate_genome函数不变
winner = population.evaluate(evaluate_genome, num_generations)

额外提示

  • 当前配置文件的initial_connection = full_direct设置合理,符合输入输出直接连接的初始网络结构。
  • 你的适应度计算函数目前都返回0,后续需要补充实际逻辑,否则所有基因组适应度相同,进化无法推进。

内容的提问来源于stack exchange,提问作者Dummy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 16:35:14