NEAT-Python 未能捕获极值
NEAT-Python fails to capture extreme values
我正在使用 NEAT-Python to mimic the course of a regular sine function based on the curve's absolute difference from 0. The configuration file has almost entirely been adopted from the basic XOR example,除了输入数量设置为 1
。偏移的方向是在实际预测步骤之后从原始数据中推断出来的,所以这实际上是关于预测 [0, 1]
.
范围内的偏移。
健身功能和大部分剩余代码也采用了帮助页面,这就是为什么我相当有信心从技术角度来看代码是一致的。从下面包含的观察到的与预测的偏移量的可视化可以看出,该模型在大多数情况下都产生了相当好的结果。但是,它无法捕获值范围的下限和上限。
任何关于如何提高算法性能的帮助,特别是在 lower/upper 边缘,将不胜感激。还是有什么方法上的限制是我到目前为止没有考虑到的?
config-feedforward
位于当前工作目录:
#--- parameters for the XOR-2 experiment ---#
[NEAT]
fitness_criterion = max
fitness_threshold = 3.9
pop_size = 150
reset_on_extinction = False
[DefaultGenome]
# node activation options
activation_default = sigmoid
activation_mutate_rate = 0.0
activation_options = sigmoid
# node aggregation options
aggregation_default = sum
aggregation_mutate_rate = 0.0
aggregation_options = sum
# node bias options
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
# 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
# node add/remove rates
node_add_prob = 0.2
node_delete_prob = 0.2
# network parameters
num_hidden = 0
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
[DefaultStagnation]
species_fitness_func = max
max_stagnation = 20
species_elitism = 2
[DefaultReproduction]
elitism = 2
survival_threshold = 0.2
NEAT 函数:
# . fitness function ----
def eval_genomes(genomes, config):
for genome_id, genome in genomes:
genome.fitness = 4.0
net = neat.nn.FeedForwardNetwork.create(genome, config)
for xi in zip(abs(x)):
output = net.activate(xi)
genome.fitness -= abs(output[0] - xi[0]) ** 2
# . neat run ----
def run(config_file, n = None):
# load configuration
config = neat.Config(neat.DefaultGenome, neat.DefaultReproduction,
neat.DefaultSpeciesSet, neat.DefaultStagnation,
config_file)
# create the population, which is the top-level object for a NEAT run
p = neat.Population(config)
# add a stdout reporter to show progress in the terminal
p.add_reporter(neat.StdOutReporter(True))
stats = neat.StatisticsReporter()
p.add_reporter(stats)
p.add_reporter(neat.Checkpointer(5))
# run for up to n generations
winner = p.run(eval_genomes, n)
return(winner)
代码:
### ENVIRONMENT ====
### . packages ----
import os
import neat
import numpy as np
import matplotlib.pyplot as plt
import random
### . sample data ----
x = np.sin(np.arange(.01, 4000 * .01, .01))
### NEAT ALGORITHM ====
### . model evolution ----
random.seed(1899)
winner = run('config-feedforward', n = 25)
### . prediction ----
## extract winning model
config = neat.Config(neat.DefaultGenome, neat.DefaultReproduction,
neat.DefaultSpeciesSet, neat.DefaultStagnation,
'config-feedforward')
winner_net = neat.nn.FeedForwardNetwork.create(winner, config)
## make predictions
y = []
for xi in zip(abs(x)):
y.append(winner_net.activate(xi))
## if required, adjust signs
for i in range(len(y)):
if (x[i] < 0):
y[i] = [x * -1 for x in y[i]]
## display sample vs. predicted data
plt.scatter(range(len(x)), x, color='#3c8dbc', label = 'observed') # blue
plt.scatter(range(len(x)), y, color='#f39c12', label = 'predicted') # orange
plt.hlines(0, xmin = 0, xmax = len(x), colors = 'grey', linestyles = 'dashed')
plt.xlabel("Index")
plt.ylabel("Offset")
plt.legend(bbox_to_anchor = (0., 1.02, 1., .102), loc = 10,
ncol = 2, mode = None, borderaxespad = 0.)
plt.show()
plt.clf()
存在不同的 NEAT 实现,因此细节可能有所不同。
通常 NEAT 通过包含一个始终处于活动状态的特殊输入神经元(post-激活 1)来处理偏差。我怀疑 bias_max_value 和 bias_min_value 决定了这个偏置神经元和隐藏神经元之间连接的最大允许强度。在我使用的 NEAT 代码中,这两个参数不存在,偏置到隐藏的连接被视为正常(有它们自己的允许范围,在我们的例子中是 -5 到 5)。
如果您使用 Sigmoid 函数,您的输出神经元将在 0 到 1 的范围内工作(考虑隐藏神经元的更快激活,也许是 RELU)。
如果你试图预测接近 0 或 1 的值,这是一个问题,因为你确实需要将你的神经元推到其范围的极限,而 Sigmoid 渐近地接近这些极端(缓慢!):
幸运的是,有一种非常简单的方法可以查看这是否是问题所在:只需重新缩放输出即可!像
out = raw_out * 1.2 - 0.1
这将使您的理论输出处于超出预期输出的范围内(在我的示例中为 -0.1 到 1.1),并且更容易达到 0 和 1(严格来说实际上是可能的)。
我正在使用 NEAT-Python to mimic the course of a regular sine function based on the curve's absolute difference from 0. The configuration file has almost entirely been adopted from the basic XOR example,除了输入数量设置为 1
。偏移的方向是在实际预测步骤之后从原始数据中推断出来的,所以这实际上是关于预测 [0, 1]
.
健身功能和大部分剩余代码也采用了帮助页面,这就是为什么我相当有信心从技术角度来看代码是一致的。从下面包含的观察到的与预测的偏移量的可视化可以看出,该模型在大多数情况下都产生了相当好的结果。但是,它无法捕获值范围的下限和上限。
任何关于如何提高算法性能的帮助,特别是在 lower/upper 边缘,将不胜感激。还是有什么方法上的限制是我到目前为止没有考虑到的?
config-feedforward
位于当前工作目录:
#--- parameters for the XOR-2 experiment ---#
[NEAT]
fitness_criterion = max
fitness_threshold = 3.9
pop_size = 150
reset_on_extinction = False
[DefaultGenome]
# node activation options
activation_default = sigmoid
activation_mutate_rate = 0.0
activation_options = sigmoid
# node aggregation options
aggregation_default = sum
aggregation_mutate_rate = 0.0
aggregation_options = sum
# node bias options
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
# 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
# node add/remove rates
node_add_prob = 0.2
node_delete_prob = 0.2
# network parameters
num_hidden = 0
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
[DefaultStagnation]
species_fitness_func = max
max_stagnation = 20
species_elitism = 2
[DefaultReproduction]
elitism = 2
survival_threshold = 0.2
NEAT 函数:
# . fitness function ----
def eval_genomes(genomes, config):
for genome_id, genome in genomes:
genome.fitness = 4.0
net = neat.nn.FeedForwardNetwork.create(genome, config)
for xi in zip(abs(x)):
output = net.activate(xi)
genome.fitness -= abs(output[0] - xi[0]) ** 2
# . neat run ----
def run(config_file, n = None):
# load configuration
config = neat.Config(neat.DefaultGenome, neat.DefaultReproduction,
neat.DefaultSpeciesSet, neat.DefaultStagnation,
config_file)
# create the population, which is the top-level object for a NEAT run
p = neat.Population(config)
# add a stdout reporter to show progress in the terminal
p.add_reporter(neat.StdOutReporter(True))
stats = neat.StatisticsReporter()
p.add_reporter(stats)
p.add_reporter(neat.Checkpointer(5))
# run for up to n generations
winner = p.run(eval_genomes, n)
return(winner)
代码:
### ENVIRONMENT ====
### . packages ----
import os
import neat
import numpy as np
import matplotlib.pyplot as plt
import random
### . sample data ----
x = np.sin(np.arange(.01, 4000 * .01, .01))
### NEAT ALGORITHM ====
### . model evolution ----
random.seed(1899)
winner = run('config-feedforward', n = 25)
### . prediction ----
## extract winning model
config = neat.Config(neat.DefaultGenome, neat.DefaultReproduction,
neat.DefaultSpeciesSet, neat.DefaultStagnation,
'config-feedforward')
winner_net = neat.nn.FeedForwardNetwork.create(winner, config)
## make predictions
y = []
for xi in zip(abs(x)):
y.append(winner_net.activate(xi))
## if required, adjust signs
for i in range(len(y)):
if (x[i] < 0):
y[i] = [x * -1 for x in y[i]]
## display sample vs. predicted data
plt.scatter(range(len(x)), x, color='#3c8dbc', label = 'observed') # blue
plt.scatter(range(len(x)), y, color='#f39c12', label = 'predicted') # orange
plt.hlines(0, xmin = 0, xmax = len(x), colors = 'grey', linestyles = 'dashed')
plt.xlabel("Index")
plt.ylabel("Offset")
plt.legend(bbox_to_anchor = (0., 1.02, 1., .102), loc = 10,
ncol = 2, mode = None, borderaxespad = 0.)
plt.show()
plt.clf()
存在不同的 NEAT 实现,因此细节可能有所不同。
通常 NEAT 通过包含一个始终处于活动状态的特殊输入神经元(post-激活 1)来处理偏差。我怀疑 bias_max_value 和 bias_min_value 决定了这个偏置神经元和隐藏神经元之间连接的最大允许强度。在我使用的 NEAT 代码中,这两个参数不存在,偏置到隐藏的连接被视为正常(有它们自己的允许范围,在我们的例子中是 -5 到 5)。
如果您使用 Sigmoid 函数,您的输出神经元将在 0 到 1 的范围内工作(考虑隐藏神经元的更快激活,也许是 RELU)。
如果你试图预测接近 0 或 1 的值,这是一个问题,因为你确实需要将你的神经元推到其范围的极限,而 Sigmoid 渐近地接近这些极端(缓慢!):
幸运的是,有一种非常简单的方法可以查看这是否是问题所在:只需重新缩放输出即可!像
out = raw_out * 1.2 - 0.1
这将使您的理论输出处于超出预期输出的范围内(在我的示例中为 -0.1 到 1.1),并且更容易达到 0 和 1(严格来说实际上是可能的)。