initial commit
This commit is contained in:
1
utils/__init__.py
Normal file
1
utils/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .config import Configer
|
||||
BIN
utils/__pycache__/__init__.cpython-39.pyc
Normal file
BIN
utils/__pycache__/__init__.cpython-39.pyc
Normal file
Binary file not shown.
BIN
utils/__pycache__/config.cpython-39.pyc
Normal file
BIN
utils/__pycache__/config.cpython-39.pyc
Normal file
Binary file not shown.
BIN
utils/__pycache__/dotdict.cpython-39.pyc
Normal file
BIN
utils/__pycache__/dotdict.cpython-39.pyc
Normal file
Binary file not shown.
78
utils/config.py
Normal file
78
utils/config.py
Normal file
@@ -0,0 +1,78 @@
|
||||
import json
|
||||
import os
|
||||
import warnings
|
||||
|
||||
from .dotdict import DotDict
|
||||
|
||||
|
||||
class Configer:
|
||||
@classmethod
|
||||
def __load_default_config(cls):
|
||||
par_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
default_config_path = os.path.join(par_dir, "./default_config.json")
|
||||
return cls.__load_config(default_config_path)
|
||||
|
||||
@classmethod
|
||||
def __load_config(cls, config_path):
|
||||
with open(config_path, "r") as f:
|
||||
text = "".join(f.readlines())
|
||||
try:
|
||||
j = json.loads(text)
|
||||
except ValueError:
|
||||
raise Exception("Invalid config")
|
||||
return DotDict.from_dict(j, "root")
|
||||
|
||||
@classmethod
|
||||
def __check_redundant_config(cls, default_config, config):
|
||||
for key in config:
|
||||
if key not in default_config:
|
||||
warnings.warn(f"Redundant config: {key} in {config.name}")
|
||||
continue
|
||||
if isinstance(default_config[key], DotDict):
|
||||
cls.__check_redundant_config(default_config[key], config[key])
|
||||
|
||||
@classmethod
|
||||
def __complete_config(cls, default_config, config):
|
||||
for key in default_config:
|
||||
if key not in config:
|
||||
config[key] = default_config[key]
|
||||
continue
|
||||
if isinstance(default_config[key], DotDict):
|
||||
cls.__complete_config(default_config[key], config[key])
|
||||
|
||||
@classmethod
|
||||
def __decorate_config(cls, config):
|
||||
if config.neat.gene.activation.options == 'all':
|
||||
config.neat.gene.activation.options = [
|
||||
"sigmoid", "tanh", "sin", "gauss", "relu", "elu", "lelu", "selu", "softplus", "identity", "clamped",
|
||||
"inv", "log", "exp", "abs", "hat", "square", "cube"
|
||||
]
|
||||
if isinstance(config.neat.gene.activation.options, str):
|
||||
config.neat.gene.activation.options = [config.neat.gene.activation.options]
|
||||
|
||||
if config.neat.gene.aggregation.options == 'all':
|
||||
config.neat.gene.aggregation.options = ["product", "sum", "max", "min", "median", "mean"]
|
||||
if isinstance(config.neat.gene.aggregation.options, str):
|
||||
config.neat.gene.aggregation.options = [config.neat.gene.aggregation.options]
|
||||
|
||||
@classmethod
|
||||
def load_config(cls, config_path=None):
|
||||
default_config = cls.__load_default_config()
|
||||
if config_path is None:
|
||||
config = DotDict("root")
|
||||
elif not os.path.exists(config_path):
|
||||
warnings.warn(f"config file {config_path} not exist!")
|
||||
config = DotDict("root")
|
||||
else:
|
||||
config = cls.__load_config(config_path)
|
||||
|
||||
cls.__check_redundant_config(default_config, config)
|
||||
cls.__complete_config(default_config, config)
|
||||
cls.__decorate_config(config)
|
||||
return config
|
||||
|
||||
@classmethod
|
||||
def write_config(cls, config, write_path):
|
||||
text = json.dumps(config, indent=2)
|
||||
with open(write_path, "w") as f:
|
||||
f.write(text)
|
||||
108
utils/default_config.json
Normal file
108
utils/default_config.json
Normal file
@@ -0,0 +1,108 @@
|
||||
{
|
||||
"basic": {
|
||||
"num_inputs": 2,
|
||||
"num_outputs": 1,
|
||||
"init_maximum_nodes": 20,
|
||||
"expands_coe": 1.5
|
||||
},
|
||||
"neat": {
|
||||
"population": {
|
||||
"fitness_criterion": "max",
|
||||
"fitness_threshold": 43.9999,
|
||||
"generation_limit": 100,
|
||||
"pop_size": 1000,
|
||||
"reset_on_extinction": "False"
|
||||
},
|
||||
"gene": {
|
||||
"bias": {
|
||||
"init_mean": 0.0,
|
||||
"init_stdev": 1.0,
|
||||
"max_value": 30.0,
|
||||
"min_value": -30.0,
|
||||
"mutate_power": 0.5,
|
||||
"mutate_rate": 0.7,
|
||||
"replace_rate": 0.1
|
||||
},
|
||||
"response": {
|
||||
"init_mean": 1.0,
|
||||
"init_stdev": 0.0,
|
||||
"max_value": 30.0,
|
||||
"min_value": -30.0,
|
||||
"mutate_power": 0.0,
|
||||
"mutate_rate": 0.0,
|
||||
"replace_rate": 0.0
|
||||
},
|
||||
"activation": {
|
||||
"default": "sigmoid",
|
||||
"options": "sigmoid",
|
||||
"mutate_rate": 0.01
|
||||
},
|
||||
"aggregation": {
|
||||
"default": "sum",
|
||||
"options": [
|
||||
"product",
|
||||
"sum",
|
||||
"max",
|
||||
"min",
|
||||
"median",
|
||||
"mean"
|
||||
],
|
||||
"mutate_rate": 0.01
|
||||
},
|
||||
"weight": {
|
||||
"init_mean": 0.0,
|
||||
"init_stdev": 1.0,
|
||||
"max_value": 30.0,
|
||||
"min_value": -30.0,
|
||||
"mutate_power": 0.5,
|
||||
"mutate_rate": 0.8,
|
||||
"replace_rate": 0.1
|
||||
},
|
||||
"enabled": {
|
||||
"mutate_rate": 0.01
|
||||
}
|
||||
},
|
||||
"genome": {
|
||||
"compatibility_disjoint_coefficient": 1.0,
|
||||
"compatibility_weight_coefficient": 0.5,
|
||||
"feedforward": "True",
|
||||
"single_structural_mutation": "False",
|
||||
"conn_add_prob": 0.5,
|
||||
"conn_delete_prob": 0.5,
|
||||
"node_add_prob": 0.2,
|
||||
"node_delete_prob": 0.2
|
||||
},
|
||||
"species": {
|
||||
"compatibility_threshold": 3.5,
|
||||
"species_fitness_func": "max",
|
||||
"max_stagnation": 20,
|
||||
"species_elitism": 2,
|
||||
"genome_elitism": 2,
|
||||
"survival_threshold": 0.2,
|
||||
"min_species_size": 1
|
||||
}
|
||||
},
|
||||
"hyperneat": {
|
||||
"substrate": {
|
||||
"type": "feedforward",
|
||||
"layers": [
|
||||
3,
|
||||
10,
|
||||
10,
|
||||
1
|
||||
],
|
||||
"x_lim": [
|
||||
-5,
|
||||
5
|
||||
],
|
||||
"y_lim": [
|
||||
-5,
|
||||
5
|
||||
],
|
||||
"threshold": 0.2,
|
||||
"max_weight": 5.0
|
||||
}
|
||||
},
|
||||
"es-hyperneat": {
|
||||
}
|
||||
}
|
||||
61
utils/dotdict.py
Normal file
61
utils/dotdict.py
Normal file
@@ -0,0 +1,61 @@
|
||||
# DotDict For Config. Case Insensitive.
|
||||
|
||||
class DotDict(dict):
|
||||
def __init__(self, name, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self["name"] = name
|
||||
|
||||
def __getattr__(self, attr):
|
||||
attr = attr.lower() # case insensitive
|
||||
if attr in self:
|
||||
return self[attr]
|
||||
else:
|
||||
raise AttributeError(f"'{self.__class__.__name__}-{self.name}' has no attribute '{attr}'")
|
||||
|
||||
def __setattr__(self, attr, value):
|
||||
attr = attr.lower() # case insensitive
|
||||
if attr not in self:
|
||||
raise AttributeError(f"'{self.__class__.__name__}-{self.name}' has no attribute '{attr}'")
|
||||
self[attr] = value
|
||||
|
||||
def __delattr__(self, attr):
|
||||
attr = attr.lower() # case insensitive
|
||||
if attr in self:
|
||||
del self[attr]
|
||||
else:
|
||||
raise AttributeError(f"{self.__class__.__name__}-{self.name} object has no attribute '{attr}'")
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, d, name):
|
||||
if not isinstance(d, dict):
|
||||
return d
|
||||
|
||||
dot_dict = cls(name)
|
||||
for key, value in d.items():
|
||||
key = key.lower() # case insensitive
|
||||
if isinstance(value, dict):
|
||||
dot_dict[key] = cls.from_dict(value, key)
|
||||
else:
|
||||
dot_dict[key] = value
|
||||
if dot_dict[key] == "True": # Fuck! Json has no bool type!
|
||||
dot_dict[key] = True
|
||||
if dot_dict[key] == "False":
|
||||
dot_dict[key] = False
|
||||
if dot_dict[key] == "None":
|
||||
dot_dict[key] = None
|
||||
return dot_dict
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
nested_dict = {
|
||||
"a": 1,
|
||||
"b": {
|
||||
"c": 2,
|
||||
"ACDeef": {
|
||||
"e": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dd = DotDict.from_dict(nested_dict, "root")
|
||||
print(dd.b.acdeef.e) # 输出:3
|
||||
Reference in New Issue
Block a user