Teknologian jakaminen

Differentiaalinen evoluution algoritmi

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

1. Esittely

Differentiaalinen evoluutio (DE) on algoritmi, joka toimii luomalla useita satunnaisia ​​yksilöitä, vertaamalla niitä ennalta määritettyihin arviointimittareihin ja säilyttämällä parhaat yksilöt, sitten luomalla uusia yksilöitä sekoittamalla jäljellä olevien yksilöiden ominaisuuksia ja toistamalla tätä prosessia ratkaistakseen globaaleja optimointiongelmia. Seuraavassa koodauksessa tämä prosessi selitetään huolellisesti kaikille.

2. Koodi

# 创建一个对象。
from typing import List, Dict, Tuple, Union

class Individual:
    def __init__(
            self,
            parameters: Dict[str, float],
            score: Union[float, None] = None
    ) -> None:
        super().__init__()
        self.parameter_values = parameters
        self.score = score
   # 该对象保存单个个体的参数和分数。具有参数的个体x=2, y=3     
parameter_value = {"x":2, "y":3}
score = 13
# 评分
def scoring(ind: Individual) -> float:
    return ind.parameter_values["x"] ** 2 + ind.parameter_values["y"] ** 2
# 创造一个群体并进化它们。
class Population:
    # 最大化方向常量
    MAXIMIZE = 1
    # 最小化方向常量
    MINIMIZE = -1

    def __init__(
            self,
            pop_size,  # 种群大小
            direction: int,  # 优化方向(1 表示最大化,-1 表示最小化)
            bounds: Dict[str, Tuple[float, float]],  # 参数的边界范围字典
            parameters: List[str]  # 参数名称列表
    ) -> None:
        """
        初始化 Population 类的实例

        参数:
        pop_size (int):种群的大小
        direction (int):优化的方向,1 表示最大化,-1 表示最小化
        bounds (Dict[str, Tuple[float, float]]):包含每个参数的边界范围的字典
        parameters (List[str]):参数的名称列表
        """
        self.pop_size = pop_size
        self.direction = direction
        self.bounds = bounds
        self.parameters = parameters
        self.individuals: List[Individual] = []  # 存储个体的列表

    def _create_individual(self) -> Individual:
        """
        内部方法,用于创建一个个体

        返回:
        Individual:创建的个体
        """
        dict_parameters = {}  # 用于存储个体的参数值
        for parameter in self.parameters:
            # 在参数的边界范围内生成随机值
            param_value = random.uniform(self.bounds[parameter][0], self.bounds[parameter][1])
            dict_parameters[parameter] = param_value
        individual = Individual(parameters=dict_parameters)  # 创建个体对象
        individual.score = scoring(individual)  # 计算个体的得分
        return individual

    def initiate(self):
        """
        初始化种群,创建指定数量的个体并添加到 individuals 列表中
        """
        for i in range(self.pop_size):
            individual = self._create_individual()
            self.individuals.append(individual)

    def get_best_individual(self) -> Individual:
        """
        获取种群中得分最优的个体

        返回:
        Individual:得分最优的个体
        """
        self.best_individual = max(self.individuals, key=lambda x: x.score * self.direction)
        return self.best_individual

    def get_worst_individual(self) -> Individual:
        """
        获取种群中得分最差的个体

        返回:
        Individual:得分最差的个体
        """
        self.best_individual = min(self.individuals, key=lambda x: x.score * self.direction)
        return self.best_individual

    def get_mean_score(self) -> float:
        """
        计算种群中个体得分的平均值

        返回:
        float:个体得分的平均值
        """
        self.mean_score = sum([ind.score for ind in self.individuals]) / len(self.individuals)
        return self.mean_score

    def get_std_score(self) -> float:
        """
        计算种群中个体得分的标准差

        返回:
        float:个体得分的标准差
        """
        self.std_score = sum([(ind.score - self.mean_score) ** 2 for ind in self.individuals]) / len(self.individuals)
        return self.std_score
        class Optimization:
    def __init__(self, f: float, cp: float, population: Population):
        """
        初始化 Optimization 类的实例

        参数:
        f (float):某个相关的浮点数参数
        cp (float):某个相关的浮点数参数
        population (Population):种群对象
        """
        self.f = f
        self.cp = cp
        self.population = population

    @staticmethod
    def _mutant_choose(population: Population) -> Tuple[Individual, Individual, Individual]:
        """
        静态方法,从种群中选择 3 个随机个体

        参数:
        population (Population):要选择个体的种群

        返回:
        Tuple[Individual, Individual, Individual]:随机选择的 3 个个体
        """
        # 从种群的个体列表中随机抽取 3 个个体
        individuals = population.individuals
        random_individuals = random.sample(individuals, 3)
        return tuple(random_individuals)

    @staticmethod
    def _handle_boundaries(parameter_value: float, bounds: Tuple[float, float]) -> float:
        """
        静态方法,处理参数值超出边界的情况

        参数:
        parameter_value (float):要检查的参数值
        bounds (Tuple[float, float]):参数的边界范围

        返回:
        float:处理后的参数值
        """
        # 如果参数值大于上界,将其设为上界
        if parameter_value > bounds[1]:
            parameter_value = bounds[1]
        # 如果参数值小于下界,将其设为下界
        elif parameter_value < bounds[0]:
            parameter_value = bounds[0]
        return parameter_value

    @staticmethod
    def _calculate_parameter(
            semi_parents: Tuple[Individual, Individual, Individual],
            parameter_name: str,
            bounds: Tuple[float, float],
            f: float
    ) -> float:
        """
        静态方法,根据半亲代计算试验个体的参数

        参数:
        semi_parents (Tuple[Individual, Individual, Individual]):三个半亲代个体
        parameter_name (str):参数的名称
        bounds (Tuple[float, float]):参数的边界范围
        f (float):某个相关的浮点数参数

        返回:
        float:计算得到的试验个体的参数值
        """
        # 根据半亲代计算试验个体的参数
        trial_parameter = semi_parents[0].parameter_values[parameter_name] + 
                          f * (semi_parents[1].parameter_values[parameter_name] -
                               semi_parents[2].parameter_values[parameter_name])
        # 处理参数值超出边界的情况
        trial_parameter = Optimization._handle_boundaries(trial_parameter, bounds)
        return trial_parameter

    def _mutation(self, population: Population) -> Individual:
        """
        执行变异操作,创建试验个体

        参数:
        population (Population):要操作的种群

        返回:
        Individual:创建的试验个体
        """
        # 选择半亲代
        semi_parents = Optimization._mutant_choose(population)
        trial_parameters = {}
        # 对于每个参数名称
        for parameter in population.parameters:
            # 计算试验个体的参数
            trial_parameter = self._calculate_parameter(
                semi_parents, parameter,
                population.bounds[parameter],
                self.f
            )
            trial_parameters[parameter] = trial_parameter
        # 创建试验个体
        trial_individual = Individual(parameters=trial_parameters)
        return trial_individual

def _crossover(self, parent: Individual, trial: Individual, parameters):
    """
    执行交叉操作,生成子代个体

    参数:
    parent (Individual):父代个体
    trial (Individual):试验个体
    parameters (List[str]):参数列表

    返回:
    Individual:生成的子代个体
    """
    child_parameters = {}
    # 对于每个参数
    for parameter in parameters:
        # 生成随机概率
        prob = random.random()
        # 根据概率决定子代参数取值来自父代还是试验个体
        if prob < self.cp:
            child_parameters[parameter] = parent.parameter_values[parameter]
        else:
            child_parameters[parameter] = trial.parameter_values[parameter]
    # 创建子代个体
    child = Individual(parameters=child_parameters)
    return child

@staticmethod
def _selection(child: Individual, parent: Individual, direction: int) -> bool:
    """
    执行选择操作,比较子代和父代个体的得分,并根据方向决定是否选择子代

    参数:
    child (Individual):子代个体
    parent (Individual):父代个体
    direction (int):优化方向(1 表示最大化,-1 表示最小化)

    返回:
    bool:如果子代更优(或得分相等且倾向于选择子代),则返回 True,否则返回 False
    """
    child.score = scoring(child)
    # 在得分相等的情况下倾向于选择子代
    if direction == Population.MAXIMIZE:
        return child.score >= parent.score
    else:
        return child.score <= parent.score


def main(self, generations: int):
    """
    主函数,执行多代的优化过程

    参数:
    generations (int):要执行的代数
    """
    population = self.population

    for gen in range(generations):
        new_individuals = []

        for i in range(population.pop_size):
            # 变异操作
            trial_individual = self._mutation(population)

            # 交叉操作
            parent = population.individuals[i]
            child = self._crossover(parent, trial_individual, population.parameters)

            # 选择操作
            if self._selection(child, parent, self.population.direction):
                new_individuals.append(child)
            else:
                new_individuals.append(parent)

        # 用新的个体更新种群
        population.individuals = new_individuals

        # 在每一代结束时更新统计信息或执行其他必要任务
        best_individual = population.get_best_individual()
        worst_individual = population.get_worst_individual()
        mean_score = population.get_mean_score()
        std_score = population.get_std_score()

        # 打印或存储关于这一代的相关信息
        print(
            f"Generation {gen + 1}: Best Score - {best_individual.score}, Worst Score - {worst_individual.score}, Mean Score - {mean_score}, Std Score - {std_score}")

    # 完成所有代后,可以返回或执行任何最终操作
    final_best_individual = population.get_best_individual()
    print(
        f"Optimization complete. Best individual: {final_best_individual.parameter_values}, Score: {final_best_individual.score}")



population = Population(
    pop_size=50,
    direction=Population.MINIMIZE,
    bounds={"x": (-100, 100), "y": (-100, 100)},
    parameters=["x", "y"]
)
population.initiate()

optimization = Optimization(
    f=0.5,
    cp=0.7,
    population=population
)

optimization.main(20)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321

3. Rajoitukset

Vaikka differentiaalinen evoluutioalgoritmi on monipuolinen, siinä ei ole puutteita. Ilmeisin näistä rajoituksista on monien metaheurististen algoritmien kohtaama paikallinen optimiteettiongelma. DE-algoritmi tai mikään geneettinen algoritmi ei takaa, että parhaat löytämänsä parametrit ovat parhaita ratkaisuja. Kuvittele syvä laakso, väestömme haluaa ylittää sen, ihmiset haluavat laskea maata, joten he voivat kaikki joutua laaksoon ja jäädä loukkuun, kun taas jossain muualla on syvempi laakso. Parametrien muuttaminen monimuotoisemmiksi ja laajempien vaiheiden kiertäminen ratkaisutilassa voi auttaa, mutta suorituskustannuksiin.