evolib 0.2.0b4.dev5__tar.gz → 0.2.0b4.dev7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {evolib-0.2.0b4.dev5/evolib.egg-info → evolib-0.2.0b4.dev7}/PKG-INFO +1 -1
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/docs/config_guide.md +3 -2
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/docs/config_parameter.md +11 -4
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/config/evonet_component_config.py +117 -25
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/initializers/evonet_initializers.py +106 -65
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/representation/evonet.py +27 -15
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7/evolib.egg-info}/PKG-INFO +1 -1
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/pyproject.toml +1 -1
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/tests/test_evonet_neuron_dynamics.py +16 -1
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/tests/test_initializer_evonet.py +10 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/LICENSE +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/MANIFEST.in +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/README.md +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/docs/api_core_individual.rst +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/docs/api_core_population.rst +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/docs/api_operators_crossover.rst +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/docs/api_operators_evonet_structural_mutation.rst +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/docs/api_operators_mutation.rst +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/docs/api_operators_replacement.rst +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/docs/api_operators_reproduction.rst +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/docs/api_operators_selection.rst +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/docs/api_operators_strategy.rst +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/docs/api_public_api.rst +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/docs/api_representation_evonet.rst +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/docs/api_representation_netvector.rst +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/docs/api_representation_vector.rst +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/docs/api_utils_benchmarks.rst +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/docs/api_utils_history_logger.rst +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/docs/api_utils_loss_functions.rst +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/docs/api_utils_plotting.rst +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/docs/conf.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/docs/getting_started.md +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/docs/index.md +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/__init__.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/api.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/config/__init__.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/config/base_component_config.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/config/component_registry.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/config/schema.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/config/vector_component_config.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/core/README.md +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/core/__init__.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/core/individual.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/core/population.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/envs/gym_wrapper.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/globals/README.md +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/globals/__init__.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/globals/numeric.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/initializers/__init__.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/initializers/net_initializers.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/initializers/registry.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/initializers/vector_initializers.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/interfaces/__init__.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/interfaces/enum_helpers.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/interfaces/enums.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/interfaces/structs.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/interfaces/types.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/io/checkpoint.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/io/serialization.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/operators/README.md +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/operators/__init__.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/operators/crossover.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/operators/evonet_structural_mutation.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/operators/heli.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/operators/mutation.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/operators/replacement.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/operators/reproduction.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/operators/selection.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/operators/strategy.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/registry/__init__.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/registry/replacement_registry.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/registry/selection_registry.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/registry/strategy_registry.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/representation/__init__.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/representation/_apply_config_mapping.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/representation/base.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/representation/composite.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/representation/dummy.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/representation/evo_params.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/representation/netvector.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/representation/vector.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/utils/README.md +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/utils/__init__.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/utils/benchmarks.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/utils/config_loader.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/utils/fitness.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/utils/heli_experiment_logger.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/utils/heli_utils.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/utils/history_logger.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/utils/lineage_logger.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/utils/loss_functions.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/utils/parallel.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/utils/plotting.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/utils/random.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib/utils/registry.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib.egg-info/SOURCES.txt +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib.egg-info/dependency_links.txt +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib.egg-info/requires.txt +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/evolib.egg-info/top_level.txt +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/01_basic_usage/01_getting_started.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/01_basic_usage/02_mutation.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/01_basic_usage/03_population_mutation.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/01_basic_usage/04_fitness.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/02_strategies/01_step_by_step_evolution.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/02_strategies/02_mu_lambda_step.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/02_strategies/03_mu_lambda.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/02_strategies/04_flexible.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/03_comparisons/01_history.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/03_comparisons/02_plotting.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/03_comparisons/03_compare_runs.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/03_comparisons/04_exponential_decay_vs_static.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/03_comparisons/05_adaptive_global_vs_static.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/03_comparisons/06_adaptive_individual_vs_static.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/03_comparisons/07_selection_comparison.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/03_comparisons/08_selection_pressure.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/03_comparisons/09_selection_vs_mutation_pressure.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/03_comparisons/10_selection_stochastic_vs_deterministic.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/03_comparisons/11_crossover_comparison.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/04_function_approximation/01_polynomial_sine.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/04_function_approximation/02_sine_point_approximation.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/04_function_approximation/03_approximation_with_noise.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/05_advanced_topics/01_fitness_landscape_exploration.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/05_advanced_topics/02_rosenbrock_surface_path.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/05_advanced_topics/03_vector_control.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/05_advanced_topics/04_vector_control_with_obstacles.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/05_advanced_topics/05_piecewise_linear_xsys.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/05_advanced_topics/06_evolving_mutation_strength_as_a_module.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/06_netvector/01_netvector_sine_approximation.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/06_netvector/02_netvector_modulated_output.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/06_netvector/03_netvector_gain_and_bias.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/07_evonet/01_sine_approximation.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/07_evonet/02_sine_delay.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/07_evonet/03_delay_bitseq_echo.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/07_evonet/04_leaky_temporal_smoothing.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/07_evonet/05_image_approximation.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/07_evonet/06_structural_xor.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/07_evonet/07_recurrent_bit_prediction.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/07_evonet/08_recurrent_timeseries.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/07_evonet/09_recurrent_trading.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/08_gym/01_frozen_lake.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/08_gym/02_cliff_walking.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/08_gym/03_cartpole.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/08_gym/04_lunar_lander.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/08_gym/05_bipedal_walker.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/09_meta_learning/01_lamarck_linear_mapping.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/examples/09_meta_learning/02_meta_mapping_baldwin.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/setup.cfg +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/tests/test_benchmarks.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/tests/test_config_loader.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/tests/test_elitism_preserves_best_fitness.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/tests/test_evonet_deepcopy.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/tests/test_evonet_vector_io.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/tests/test_initializer_net.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/tests/test_mutation.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/tests/test_population.py +0 -0
- {evolib-0.2.0b4.dev5 → evolib-0.2.0b4.dev7}/tests/test_selection.py +0 -0
|
@@ -148,14 +148,15 @@ modules:
|
|
|
148
148
|
initializer: normal_evonet
|
|
149
149
|
weights:
|
|
150
150
|
bounds: [-5.0, 5.0]
|
|
151
|
-
|
|
151
|
+
bias:
|
|
152
|
+
bounds: [-1.0, 1.0]
|
|
152
153
|
|
|
153
154
|
recurrent: direct # REQUIRED for delay to have any effect
|
|
154
155
|
|
|
155
156
|
# NOTE: Delays only apply to recurrent connections.
|
|
156
157
|
# If `recurrent` is not enabled, this block has no effect.
|
|
157
158
|
delay:
|
|
158
|
-
initializer:
|
|
159
|
+
initializer: uniform # uniform | fixed
|
|
159
160
|
bounds: [1, 8] # only for random
|
|
160
161
|
# value: 3 # only for fixed
|
|
161
162
|
|
|
@@ -188,7 +188,7 @@ modules:
|
|
|
188
188
|
| `activation` | str \| list[str] | — | If list: activation per layer. If str: used for non-input layers; input layer is treated as linear. |
|
|
189
189
|
| `initializer` | str | — | Network initialization method (e.g. `normal_evonet`, `unconnected_evonet`). |
|
|
190
190
|
| `weights` | dict | — | Weight init and bounds configuration (initializer, bounds, optional params). |
|
|
191
|
-
| `
|
|
191
|
+
| `bias` | dict | — | Bias init and bounds configuration (initializer, bounds, optional params). |
|
|
192
192
|
| `neuron_dynamics` | list[dict] \| null | null | Optional per-layer neuron dynamics specification. Must match `len(dim)`. |
|
|
193
193
|
| `mutation` | dict \| null | null | Mutation settings for weights, biases, activations, delay, and structure. |
|
|
194
194
|
| `crossover` | dict \| null | null | Optional crossover settings (weight/bias level). |
|
|
@@ -200,6 +200,13 @@ modules:
|
|
|
200
200
|
|bounds | list[float] | [-1.0, 1.0] | Hard clipping bounds [min_w, max_w]. |
|
|
201
201
|
|std | float | null |null | Std-dev for normal (if used). |
|
|
202
202
|
|
|
203
|
+
##### bias block
|
|
204
|
+
|Parameter | Type | Default | Explanation |
|
|
205
|
+
|------------|-------|-----------|-------------|
|
|
206
|
+
|initializer | str | "normal" | Weight initializer preset (normal, uniform, zero, …). |
|
|
207
|
+
|bounds | list[float] | [-1.0, 1.0] | Hard clipping bounds [min_w, max_w]. |
|
|
208
|
+
|std | float | null |null | Std-dev for normal (if used). |
|
|
209
|
+
|
|
203
210
|
---
|
|
204
211
|
|
|
205
212
|
#### EvoNet Initializer
|
|
@@ -210,7 +217,7 @@ The EvoNet module uses:
|
|
|
210
217
|
|---------------------|------------------------------------|----------------------------------|---------------------------------------------|
|
|
211
218
|
| `normal_evonet` | Normal(0, 0.5) | Normal(0, 0.5) | Default initializer for general use |
|
|
212
219
|
| `unconnected_evonet`| None | 0 | For pure structural growth; empty topology |
|
|
213
|
-
| `random_evonet` | Random | Uniform(
|
|
220
|
+
| `random_evonet` | Random | Uniform(bias bounds) | For broader stochastic exploration |
|
|
214
221
|
| `zero_evonet` | 0 | 0 | Deterministic baseline; debugging |
|
|
215
222
|
| `identity_evonet` | Small random | Small random | Designed for stable recurrent memory |
|
|
216
223
|
|
|
@@ -268,7 +275,7 @@ modules:
|
|
|
268
275
|
type: evonet
|
|
269
276
|
...
|
|
270
277
|
delay:
|
|
271
|
-
initializer:
|
|
278
|
+
initializer: uniform # uniform | fixed
|
|
272
279
|
bounds: [1, 8] # only for random
|
|
273
280
|
# value: 3 # only for fixed
|
|
274
281
|
```
|
|
@@ -433,7 +440,7 @@ modules:
|
|
|
433
440
|
initializer: normal_evonet
|
|
434
441
|
|
|
435
442
|
delay:
|
|
436
|
-
initializer:
|
|
443
|
+
initializer: uniform
|
|
437
444
|
bounds: [1, 8]
|
|
438
445
|
|
|
439
446
|
mutation:
|
|
@@ -31,45 +31,142 @@ from evolib.config.base_component_config import (
|
|
|
31
31
|
StructuralMutationConfig,
|
|
32
32
|
)
|
|
33
33
|
|
|
34
|
+
Bounds = Tuple[float, float]
|
|
35
|
+
|
|
34
36
|
|
|
35
37
|
class WeightsConfig(BaseModel):
|
|
36
|
-
|
|
38
|
+
# None means: no parameter-level initialization requested (preset may initialize).
|
|
39
|
+
initializer: Optional[str] = None # normal | uniform | zero | None
|
|
40
|
+
std: Optional[float] = None
|
|
41
|
+
bounds: Bounds = (-1.0, 1.0) # mutation/search bounds
|
|
42
|
+
init_bounds: Optional[Bounds] = None # init-time clipping bounds
|
|
37
43
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
@model_validator(mode="after")
|
|
45
|
+
def _validate(self) -> "WeightsConfig":
|
|
46
|
+
# Validate bounds
|
|
47
|
+
lo, hi = self.bounds
|
|
48
|
+
if lo >= hi:
|
|
49
|
+
raise ValueError("weights.bounds must satisfy lower < upper")
|
|
50
|
+
|
|
51
|
+
if self.init_bounds is not None:
|
|
52
|
+
ilo, ihi = self.init_bounds
|
|
53
|
+
if ilo >= ihi:
|
|
54
|
+
raise ValueError("weights.init_bounds must satisfy lower < upper")
|
|
55
|
+
if not (lo <= ilo and ihi <= hi):
|
|
56
|
+
raise ValueError("weights.init_bounds must lie within weights.bounds")
|
|
57
|
+
|
|
58
|
+
# Validate initializer-specific fields
|
|
59
|
+
if self.initializer is None:
|
|
60
|
+
# Preset-based initialization
|
|
61
|
+
if self.std is not None:
|
|
62
|
+
raise ValueError(
|
|
63
|
+
"weights.std is not allowed when " "weights.initializer is not set"
|
|
64
|
+
)
|
|
65
|
+
return self
|
|
66
|
+
|
|
67
|
+
if self.initializer == "normal":
|
|
68
|
+
if self.std is None or self.std <= 0:
|
|
69
|
+
raise ValueError(
|
|
70
|
+
"weights.std must be set and > 0 for initializer=normal"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
elif self.initializer in ("uniform", "zero"):
|
|
74
|
+
if self.std is not None:
|
|
75
|
+
raise ValueError("weights.std is only allowed for initializer=normal")
|
|
76
|
+
|
|
77
|
+
else:
|
|
78
|
+
raise ValueError(f"Unknown weights initializer: {self.initializer}")
|
|
79
|
+
|
|
80
|
+
return self
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class BiasConfig(BaseModel):
|
|
84
|
+
# None means: no parameter-level initialization requested (preset may initialize).
|
|
85
|
+
initializer: Optional[str] = None # fixed | normal | uniform | zero | None
|
|
86
|
+
std: Optional[float] = None
|
|
87
|
+
value: Optional[float] = None
|
|
88
|
+
bounds: Bounds = (-0.5, 0.5) # mutation/search bounds
|
|
89
|
+
init_bounds: Optional[Bounds] = None # init-time clipping bounds (optional)
|
|
90
|
+
|
|
91
|
+
@model_validator(mode="after")
|
|
92
|
+
def _validate(self) -> "BiasConfig":
|
|
93
|
+
# Validate bounds
|
|
94
|
+
lo, hi = self.bounds
|
|
95
|
+
if lo >= hi:
|
|
96
|
+
raise ValueError("bias.bounds must satisfy lower < upper")
|
|
97
|
+
|
|
98
|
+
if self.init_bounds is not None:
|
|
99
|
+
ilo, ihi = self.init_bounds
|
|
100
|
+
if ilo >= ihi:
|
|
101
|
+
raise ValueError("bias.init_bounds must satisfy lower < upper")
|
|
102
|
+
if not (lo <= ilo and ihi <= hi):
|
|
103
|
+
raise ValueError("bias.init_bounds must lie within bias.bounds")
|
|
104
|
+
|
|
105
|
+
# Validate initializer-specific fields
|
|
106
|
+
if self.initializer is None:
|
|
107
|
+
# Preset-based initialization
|
|
108
|
+
if self.std is not None:
|
|
109
|
+
raise ValueError(
|
|
110
|
+
"bias.std is not allowed when bias.initializer is not set"
|
|
111
|
+
)
|
|
112
|
+
if self.value is not None:
|
|
113
|
+
raise ValueError(
|
|
114
|
+
"bias.value is not allowed when bias.initializer is not set"
|
|
115
|
+
)
|
|
116
|
+
return self
|
|
117
|
+
|
|
118
|
+
if self.initializer == "fixed":
|
|
119
|
+
if self.value is None:
|
|
120
|
+
raise ValueError("bias.value is required for initializer=fixed")
|
|
121
|
+
if self.std is not None:
|
|
122
|
+
raise ValueError("bias.std is not allowed for initializer=fixed")
|
|
123
|
+
|
|
124
|
+
elif self.initializer == "normal":
|
|
125
|
+
if self.std is None or self.std <= 0:
|
|
126
|
+
raise ValueError("bias.std must be set and > 0 for initializer=normal")
|
|
127
|
+
if self.value is not None:
|
|
128
|
+
raise ValueError("bias.value is only allowed for initializer=fixed")
|
|
129
|
+
|
|
130
|
+
elif self.initializer in ("uniform", "zero"):
|
|
131
|
+
if self.std is not None:
|
|
132
|
+
raise ValueError("bias.std is only allowed for initializer=normal")
|
|
133
|
+
if self.value is not None:
|
|
134
|
+
raise ValueError("bias.value is only allowed for initializer=fixed")
|
|
135
|
+
|
|
136
|
+
else:
|
|
137
|
+
raise ValueError(f"Unknown bias initializer: {self.initializer}")
|
|
138
|
+
|
|
139
|
+
return self
|
|
43
140
|
|
|
44
141
|
|
|
45
142
|
class DelayConfig(BaseModel):
|
|
46
143
|
"""Delay initialization for recurrent connections."""
|
|
47
144
|
|
|
48
|
-
initializer: Literal["
|
|
49
|
-
default="
|
|
145
|
+
initializer: Literal["fixed", "uniform"] = Field(
|
|
146
|
+
default="fixed",
|
|
50
147
|
description="Delay initializer for recurrent connections.",
|
|
51
148
|
)
|
|
52
149
|
|
|
53
150
|
value: Optional[int] = Field(
|
|
54
151
|
default=None,
|
|
55
152
|
ge=1,
|
|
56
|
-
description="Fixed delay value (required for initializer=
|
|
153
|
+
description="Fixed delay value (required for initializer=fixed).",
|
|
57
154
|
)
|
|
58
155
|
|
|
59
156
|
bounds: Optional[Tuple[int, int]] = Field(
|
|
60
157
|
default=None,
|
|
61
158
|
description="Inclusive [min, max] delay bounds (required for "
|
|
62
|
-
"initializer=
|
|
159
|
+
"initializer=uniform).",
|
|
63
160
|
)
|
|
64
161
|
|
|
65
162
|
@model_validator(mode="after")
|
|
66
163
|
def _validate(self) -> "DelayConfig":
|
|
67
|
-
if self.initializer == "
|
|
164
|
+
if self.initializer == "fixed":
|
|
68
165
|
if self.value is None:
|
|
69
|
-
raise ValueError("delay.value is required for initializer=
|
|
70
|
-
elif self.initializer == "
|
|
166
|
+
raise ValueError("delay.value is required for initializer=fixed")
|
|
167
|
+
elif self.initializer == "uniform":
|
|
71
168
|
if self.bounds is None:
|
|
72
|
-
raise ValueError("delay.bounds is required for initializer=
|
|
169
|
+
raise ValueError("delay.bounds is required for initializer=uniform")
|
|
73
170
|
lo, hi = self.bounds
|
|
74
171
|
if lo < 1 or hi < 1:
|
|
75
172
|
raise ValueError("delay bounds must be >= 1 (recurrent-only)")
|
|
@@ -96,9 +193,13 @@ class EvoNetComponentConfig(BaseModel):
|
|
|
96
193
|
|
|
97
194
|
weights:
|
|
98
195
|
initializer: normal
|
|
196
|
+
std: 0.5
|
|
99
197
|
bounds: [-1.0, 1.0]
|
|
100
198
|
|
|
101
|
-
|
|
199
|
+
bias:
|
|
200
|
+
initializer: uniform
|
|
201
|
+
bounds: [-0.5, 0.5]
|
|
202
|
+
|
|
102
203
|
mutation:
|
|
103
204
|
strategy: constant
|
|
104
205
|
probability: 0.8
|
|
@@ -151,7 +252,7 @@ class EvoNetComponentConfig(BaseModel):
|
|
|
151
252
|
|
|
152
253
|
# Numeric bounds for values; used by initialization and mutation
|
|
153
254
|
weights: WeightsConfig = Field(default_factory=WeightsConfig)
|
|
154
|
-
|
|
255
|
+
bias: BiasConfig = Field(default_factory=BiasConfig)
|
|
155
256
|
|
|
156
257
|
# Optional delay initialization for recurrent connections
|
|
157
258
|
delay: Optional[DelayConfig] = None
|
|
@@ -192,15 +293,6 @@ class EvoNetComponentConfig(BaseModel):
|
|
|
192
293
|
raise ValueError("All layer sizes in dim must be non-negative integers")
|
|
193
294
|
return dim
|
|
194
295
|
|
|
195
|
-
@field_validator("bias_bounds")
|
|
196
|
-
@classmethod
|
|
197
|
-
def check_bias_bounds(cls, bounds: Tuple[float, float]) -> Tuple[float, float]:
|
|
198
|
-
"""Validate that bias_bounds are well-formed (min < max)."""
|
|
199
|
-
low, high = bounds
|
|
200
|
-
if low >= high:
|
|
201
|
-
raise ValueError("bias_bounds must satisfy min < max")
|
|
202
|
-
return bounds
|
|
203
|
-
|
|
204
296
|
@field_validator("activation")
|
|
205
297
|
@classmethod
|
|
206
298
|
def validate_activation_length(
|
|
@@ -18,6 +18,74 @@ from evolib.interfaces.enum_helpers import resolve_recurrent_kinds
|
|
|
18
18
|
from evolib.representation.evonet import EvoNet
|
|
19
19
|
|
|
20
20
|
|
|
21
|
+
def _clip(x: np.ndarray, bounds: tuple[float, float]) -> np.ndarray:
|
|
22
|
+
lo, hi = bounds
|
|
23
|
+
return np.clip(x, lo, hi)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _apply_weights_init(para: EvoNet, cfg: EvoNetComponentConfig) -> None:
|
|
27
|
+
weights_cfg = cfg.weights
|
|
28
|
+
size = para.net.num_weights
|
|
29
|
+
|
|
30
|
+
if weights_cfg.initializer is None:
|
|
31
|
+
return
|
|
32
|
+
|
|
33
|
+
elif weights_cfg.initializer == "zero":
|
|
34
|
+
weights = np.zeros(size, dtype=float)
|
|
35
|
+
|
|
36
|
+
elif weights_cfg.initializer == "uniform":
|
|
37
|
+
# uniform uses init_bounds if present, otherwise bounds
|
|
38
|
+
lo, hi = weights_cfg.init_bounds or weights_cfg.bounds
|
|
39
|
+
weights = np.random.uniform(lo, hi, size=size)
|
|
40
|
+
|
|
41
|
+
elif weights_cfg.initializer == "normal":
|
|
42
|
+
assert weights_cfg.std is not None
|
|
43
|
+
weights = np.random.normal(loc=0.0, scale=weights_cfg.std, size=size)
|
|
44
|
+
|
|
45
|
+
# clip ONLY if init_bounds explicitly provided
|
|
46
|
+
if weights_cfg.init_bounds is not None:
|
|
47
|
+
lo, hi = weights_cfg.init_bounds
|
|
48
|
+
weights = np.clip(weights, lo, hi)
|
|
49
|
+
|
|
50
|
+
else:
|
|
51
|
+
raise ValueError(f"Unknown weights initializer: {weights_cfg.initializer}")
|
|
52
|
+
|
|
53
|
+
para.net.set_weights(weights)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _apply_bias_init(para: EvoNet, cfg: EvoNetComponentConfig) -> None:
|
|
57
|
+
bias_cfg = cfg.bias
|
|
58
|
+
size = para.net.num_biases
|
|
59
|
+
|
|
60
|
+
if bias_cfg.initializer is None:
|
|
61
|
+
return
|
|
62
|
+
|
|
63
|
+
elif bias_cfg.initializer == "zero":
|
|
64
|
+
bias = np.zeros(size, dtype=float)
|
|
65
|
+
|
|
66
|
+
elif bias_cfg.initializer == "fixed":
|
|
67
|
+
assert bias_cfg.value is not None
|
|
68
|
+
bias = np.full(size, float(bias_cfg.value), dtype=float)
|
|
69
|
+
|
|
70
|
+
elif bias_cfg.initializer == "uniform":
|
|
71
|
+
lo, hi = bias_cfg.init_bounds or bias_cfg.bounds
|
|
72
|
+
bias = np.random.uniform(lo, hi, size=size)
|
|
73
|
+
|
|
74
|
+
elif bias_cfg.initializer == "normal":
|
|
75
|
+
assert bias_cfg.std is not None
|
|
76
|
+
bias = np.random.normal(loc=0.0, scale=bias_cfg.std, size=size)
|
|
77
|
+
|
|
78
|
+
# clip only if init_bounds explicitly provided
|
|
79
|
+
if bias_cfg.init_bounds is not None:
|
|
80
|
+
lo, hi = bias_cfg.init_bounds
|
|
81
|
+
bias = np.clip(bias, lo, hi)
|
|
82
|
+
|
|
83
|
+
else:
|
|
84
|
+
raise ValueError(f"Unknown bias initializer: {bias_cfg.initializer}")
|
|
85
|
+
|
|
86
|
+
para.net.set_biases(bias)
|
|
87
|
+
|
|
88
|
+
|
|
21
89
|
def _apply_delay_init(para: EvoNet, cfg: EvoNetComponentConfig) -> None:
|
|
22
90
|
"""Initialize delay on recurrent connections only."""
|
|
23
91
|
|
|
@@ -26,19 +94,19 @@ def _apply_delay_init(para: EvoNet, cfg: EvoNetComponentConfig) -> None:
|
|
|
26
94
|
|
|
27
95
|
delay_cfg: DelayConfig = cfg.delay
|
|
28
96
|
|
|
29
|
-
for
|
|
30
|
-
if
|
|
97
|
+
for connection in para.net.get_all_connections():
|
|
98
|
+
if connection.type is not ConnectionType.RECURRENT:
|
|
31
99
|
continue
|
|
32
100
|
|
|
33
|
-
if delay_cfg.initializer == "
|
|
101
|
+
if delay_cfg.initializer == "uniform" and delay_cfg.bounds is not None:
|
|
34
102
|
assert delay_cfg.bounds is not None
|
|
35
103
|
lo, hi = delay_cfg.bounds
|
|
36
|
-
|
|
104
|
+
delay = int(np.random.randint(lo, hi + 1))
|
|
37
105
|
else:
|
|
38
106
|
assert delay_cfg.value is not None
|
|
39
|
-
|
|
107
|
+
delay = int(delay_cfg.value)
|
|
40
108
|
|
|
41
|
-
|
|
109
|
+
connection.set_delay(delay)
|
|
42
110
|
|
|
43
111
|
|
|
44
112
|
def _build_architecture(
|
|
@@ -121,80 +189,57 @@ def initializer_unconnected_evonet(config: FullConfig, module: str) -> EvoNet:
|
|
|
121
189
|
para.apply_config(cfg)
|
|
122
190
|
|
|
123
191
|
_build_architecture(para, cfg, connection_init="none")
|
|
124
|
-
|
|
125
|
-
# Initialize biases
|
|
126
|
-
para.net.set_biases(np.zeros(para.net.num_biases))
|
|
192
|
+
_apply_bias_init(para, cfg)
|
|
127
193
|
|
|
128
194
|
return para
|
|
129
195
|
|
|
130
196
|
|
|
131
197
|
def initializer_normal_evonet(config: FullConfig, module: str) -> EvoNet:
|
|
132
198
|
"""
|
|
133
|
-
|
|
199
|
+
Build a standard EvoNet architecture and initialize parameters according to the
|
|
200
|
+
explicit configuration blocks.
|
|
134
201
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
202
|
+
- Topology is created via `_build_architecture(...)`.
|
|
203
|
+
- Weights are initialized using `cfg.weights`.
|
|
204
|
+
- Biases are initialized using `cfg.bias`.
|
|
205
|
+
- Delay (if configured) is initialized using `cfg.delay`.
|
|
138
206
|
|
|
139
|
-
|
|
140
|
-
|
|
207
|
+
No implicit parameter initialization is performed here.
|
|
208
|
+
All parameter distributions are controlled explicitly via the config.
|
|
141
209
|
"""
|
|
210
|
+
|
|
142
211
|
para = EvoNet()
|
|
143
212
|
cfg = config.modules[module].model_copy(deep=True)
|
|
144
213
|
para.apply_config(cfg)
|
|
145
214
|
|
|
146
|
-
_build_architecture(para, cfg)
|
|
215
|
+
_build_architecture(para, cfg, connection_init="zero")
|
|
147
216
|
_apply_delay_init(para, cfg)
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
weights = np.random.normal(loc=0.0, scale=0.5, size=para.net.num_weights)
|
|
151
|
-
biases = np.random.normal(loc=0.0, scale=0.5, size=para.net.num_biases)
|
|
152
|
-
|
|
153
|
-
para.net.set_weights(weights)
|
|
154
|
-
para.net.set_biases(biases)
|
|
217
|
+
_apply_weights_init(para, cfg)
|
|
218
|
+
_apply_bias_init(para, cfg)
|
|
155
219
|
return para
|
|
156
220
|
|
|
157
221
|
|
|
158
222
|
def initializer_random_evonet(config: FullConfig, module: str) -> EvoNet:
|
|
159
223
|
"""
|
|
160
|
-
|
|
161
|
-
(fallback: weight_bounds, bias_bounds).
|
|
162
|
-
|
|
163
|
-
Args:
|
|
164
|
-
config (FullConfig): Full experiment configuration
|
|
165
|
-
module (str): Module name
|
|
224
|
+
Backward-compatible alias for the standard EvoNet initializer. Will be removed.
|
|
166
225
|
|
|
167
|
-
|
|
168
|
-
|
|
226
|
+
Parameter initialization is controlled by `cfg.weights`, `cfg.bias`,
|
|
227
|
+
and `cfg.delay`.
|
|
169
228
|
"""
|
|
170
|
-
|
|
171
|
-
cfg = config.modules[module].model_copy(deep=True)
|
|
172
|
-
para.apply_config(cfg)
|
|
173
|
-
|
|
174
|
-
_build_architecture(para, cfg, connection_init="random")
|
|
175
|
-
_apply_delay_init(para, cfg)
|
|
176
|
-
|
|
177
|
-
bias_bounds = cfg.bias_bounds or (-0.5, 0.5)
|
|
178
|
-
min_bias = bias_bounds[0]
|
|
179
|
-
max_bias = bias_bounds[1]
|
|
180
|
-
|
|
181
|
-
biases = np.random.uniform(min_bias, max_bias, size=para.net.num_biases)
|
|
182
|
-
|
|
183
|
-
para.net.set_biases(biases)
|
|
184
|
-
return para
|
|
229
|
+
return initializer_normal_evonet(config, module)
|
|
185
230
|
|
|
186
231
|
|
|
187
232
|
def initializer_zero_evonet(config: FullConfig, module: str) -> EvoNet:
|
|
188
233
|
"""
|
|
189
|
-
|
|
234
|
+
Build a standard EvoNet architecture and initialize all parameters to zero.
|
|
190
235
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
236
|
+
- All connection weights are set to 0.
|
|
237
|
+
- All biases are set to 0.
|
|
238
|
+
- Delay initialization follows `cfg.delay` if applicable.
|
|
194
239
|
|
|
195
|
-
|
|
196
|
-
EvoNet: Initialized EvoNet representation
|
|
240
|
+
This initializer ignores `cfg.weights` and `cfg.bias` distributions.
|
|
197
241
|
"""
|
|
242
|
+
|
|
198
243
|
para = EvoNet()
|
|
199
244
|
cfg = config.modules[module].model_copy(deep=True)
|
|
200
245
|
para.apply_config(cfg)
|
|
@@ -202,27 +247,23 @@ def initializer_zero_evonet(config: FullConfig, module: str) -> EvoNet:
|
|
|
202
247
|
_build_architecture(para, cfg, connection_init="zero")
|
|
203
248
|
_apply_delay_init(para, cfg)
|
|
204
249
|
|
|
250
|
+
para.net.set_weights(np.zeros(para.net.num_weights))
|
|
205
251
|
para.net.set_biases(np.zeros(para.net.num_biases))
|
|
252
|
+
|
|
206
253
|
return para
|
|
207
254
|
|
|
208
255
|
|
|
209
256
|
def initializer_identity_evonet(config: FullConfig, module: str) -> EvoNet:
|
|
210
257
|
"""
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
- All feedforward weights are near-zero
|
|
214
|
-
- Self-recurrent connections get weight ~0.8 (memory)
|
|
215
|
-
- Biases are randomized slightly to break symmetry
|
|
258
|
+
Build a feedforward EvoNet and initialize parameters with an identity-like
|
|
259
|
+
structure.
|
|
216
260
|
|
|
217
|
-
|
|
218
|
-
|
|
261
|
+
- Feedforward connections are created normally.
|
|
262
|
+
- Self-recurrent connections are added explicitly.
|
|
263
|
+
- Weights and biases are set to fixed values
|
|
264
|
+
to approximate identity behavior.
|
|
219
265
|
|
|
220
|
-
|
|
221
|
-
config (FullConfig): Full experiment configuration
|
|
222
|
-
module (str): Name of the EvoNet module in the config
|
|
223
|
-
|
|
224
|
-
Returns:
|
|
225
|
-
EvoNet: Initialized network with identity-style dynamics
|
|
266
|
+
This preset intentionally overrides standard parameter initialization.
|
|
226
267
|
"""
|
|
227
268
|
|
|
228
269
|
SELF_LOOP_WEIGHT = 0.8
|
|
@@ -111,7 +111,7 @@ class EvoNet(ParaBase):
|
|
|
111
111
|
|
|
112
112
|
# Bounds
|
|
113
113
|
self.weight_bounds = cfg.weights.bounds or (-1.0, 1.0)
|
|
114
|
-
self.bias_bounds = cfg.
|
|
114
|
+
self.bias_bounds = cfg.bias.bounds or (-0.5, 0.5)
|
|
115
115
|
|
|
116
116
|
self.connection_scope = cfg.connection_scope
|
|
117
117
|
self.connection_density = cfg.connection_density
|
|
@@ -156,7 +156,11 @@ class EvoNet(ParaBase):
|
|
|
156
156
|
raise ValueError("mutation_strength must be set.")
|
|
157
157
|
|
|
158
158
|
mutation_strength = self.evo_params.mutation_strength
|
|
159
|
-
mutation_probability =
|
|
159
|
+
mutation_probability = (
|
|
160
|
+
self.evo_params.mutation_probability
|
|
161
|
+
if self.evo_params.mutation_probability is not None
|
|
162
|
+
else 1.0
|
|
163
|
+
)
|
|
160
164
|
low, high = self.weight_bounds or (-np.inf, np.inf)
|
|
161
165
|
|
|
162
166
|
for connection in self.net.get_all_connections():
|
|
@@ -166,12 +170,18 @@ class EvoNet(ParaBase):
|
|
|
166
170
|
|
|
167
171
|
# Biases (optional override)
|
|
168
172
|
if self.bias_evo_params is not None:
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
+
if self.bias_evo_params.mutation_strength is not None:
|
|
174
|
+
bias_strength = self.bias_evo_params.mutation_strength
|
|
175
|
+
else:
|
|
176
|
+
bias_strength = mutation_strength
|
|
177
|
+
|
|
178
|
+
if self.bias_evo_params.mutation_probability is not None:
|
|
179
|
+
bias_probability = self.bias_evo_params.mutation_probability
|
|
180
|
+
else:
|
|
181
|
+
bias_probability = mutation_probability
|
|
173
182
|
else:
|
|
174
|
-
bias_strength
|
|
183
|
+
bias_strength = mutation_strength
|
|
184
|
+
bias_probability = mutation_probability
|
|
175
185
|
|
|
176
186
|
low, high = self.bias_bounds or (-np.inf, np.inf)
|
|
177
187
|
for neuron in self.net.get_all_neurons():
|
|
@@ -344,7 +354,11 @@ class EvoNet(ParaBase):
|
|
|
344
354
|
# If Bias-Override exists
|
|
345
355
|
if self.bias_evo_params is not None:
|
|
346
356
|
bep = self.bias_evo_params
|
|
347
|
-
|
|
357
|
+
|
|
358
|
+
# Use per-scope strategy if set; otherwise fall back to global.
|
|
359
|
+
bias_strategy = bep.mutation_strategy or ep.mutation_strategy
|
|
360
|
+
|
|
361
|
+
if bias_strategy == MutationStrategy.EXPONENTIAL_DECAY:
|
|
348
362
|
bep.mutation_strength = exponential_mutation_strength(
|
|
349
363
|
bep, generation, max_generations
|
|
350
364
|
)
|
|
@@ -352,10 +366,10 @@ class EvoNet(ParaBase):
|
|
|
352
366
|
bep, generation, max_generations
|
|
353
367
|
)
|
|
354
368
|
|
|
355
|
-
elif
|
|
369
|
+
elif bias_strategy == MutationStrategy.ADAPTIVE_GLOBAL:
|
|
356
370
|
if diversity_ema is None:
|
|
357
371
|
raise ValueError(
|
|
358
|
-
"diversity_ema must be provided for ADAPTIVE_GLOBAL (biases)"
|
|
372
|
+
"diversity_ema must be provided for " "ADAPTIVE_GLOBAL (biases)"
|
|
359
373
|
)
|
|
360
374
|
if bep.mutation_strength is None or bep.mutation_probability is None:
|
|
361
375
|
raise ValueError(
|
|
@@ -369,8 +383,7 @@ class EvoNet(ParaBase):
|
|
|
369
383
|
bep.mutation_strength, diversity_ema, bep
|
|
370
384
|
)
|
|
371
385
|
|
|
372
|
-
elif
|
|
373
|
-
# Ensure tau is initialized
|
|
386
|
+
elif bias_strategy == MutationStrategy.ADAPTIVE_INDIVIDUAL:
|
|
374
387
|
if bep.tau is None or bep.tau == 0.0:
|
|
375
388
|
bep.tau = adapted_tau(len(self.get_vector()))
|
|
376
389
|
|
|
@@ -379,8 +392,8 @@ class EvoNet(ParaBase):
|
|
|
379
392
|
or bep.max_mutation_strength is None
|
|
380
393
|
):
|
|
381
394
|
raise ValueError(
|
|
382
|
-
"biases override requires min/max mutation_strength
|
|
383
|
-
"ADAPTIVE_INDIVIDUAL."
|
|
395
|
+
"biases override requires min/max mutation_strength "
|
|
396
|
+
"for ADAPTIVE_INDIVIDUAL."
|
|
384
397
|
)
|
|
385
398
|
if self.bias_bounds is None:
|
|
386
399
|
raise ValueError("bias_bounds must be set for bias adaptation.")
|
|
@@ -389,7 +402,6 @@ class EvoNet(ParaBase):
|
|
|
389
402
|
bep.min_mutation_strength, bep.max_mutation_strength
|
|
390
403
|
)
|
|
391
404
|
|
|
392
|
-
# Perform adaptive update
|
|
393
405
|
bounds = (bep.min_mutation_strength, bep.max_mutation_strength)
|
|
394
406
|
bep.mutation_strength = adapt_mutation_strength(bep, bounds)
|
|
395
407
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "evolib"
|
|
7
|
-
version = "0.2.0b4.
|
|
7
|
+
version = "0.2.0b4.dev7"
|
|
8
8
|
description = "A modular framework for evolutionary strategies and neuroevolution."
|
|
9
9
|
authors = [
|
|
10
10
|
{ name = "EvoLib", email = "evolib@dismail.de" }
|
|
@@ -17,6 +17,16 @@ def test_neuron_dynamics_config_length_matches_dim() -> None:
|
|
|
17
17
|
dim=[1, 2, 1],
|
|
18
18
|
activation=["linear", "tanh", "tanh"],
|
|
19
19
|
initializer="zero_evonet",
|
|
20
|
+
weights={
|
|
21
|
+
"initializer": "normal",
|
|
22
|
+
"std": 0.5,
|
|
23
|
+
"bounds": [-1.0, 1.0],
|
|
24
|
+
},
|
|
25
|
+
bias={
|
|
26
|
+
"initializer": "normal",
|
|
27
|
+
"std": 0.1,
|
|
28
|
+
"bounds": [-0.5, 0.5],
|
|
29
|
+
},
|
|
20
30
|
neuron_dynamics=[
|
|
21
31
|
{"name": "standard", "params": {}},
|
|
22
32
|
{"name": "standard", "params": {}},
|
|
@@ -44,9 +54,14 @@ def test_neuron_dynamics_applied_to_neurons() -> None:
|
|
|
44
54
|
"connection_density": 1.0,
|
|
45
55
|
"weights": {
|
|
46
56
|
"initializer": "normal",
|
|
57
|
+
"std": 0.5,
|
|
47
58
|
"bounds": [-1.0, 1.0],
|
|
48
59
|
},
|
|
49
|
-
"
|
|
60
|
+
"bias": {
|
|
61
|
+
"initializer": "normal",
|
|
62
|
+
"std": 0.1,
|
|
63
|
+
"bounds": [-0.5, 0.5],
|
|
64
|
+
},
|
|
50
65
|
"neuron_dynamics": [
|
|
51
66
|
{"name": "standard", "params": {}},
|
|
52
67
|
{"name": "leaky", "params": {"alpha": 0.25}},
|