- •Постановка задачи:
- •Формализовать описание задачи в математическом виде. Выделить жесткие и мягкие ограничения.
- •Описать представление решения в виде хромосомы. Пояснить выбранное представление и какие ограничения есть на хромосому.
- •Разработать метрику для оценки качества решения. Пояснить разработанную метрику, и как она позволяет соблюдать мягкие и жесткие ограничения.
- •Выполнение га:
- •Выбрать операции для га: метод отбора, метод скрещивания, метод мутации. Обосновать выбор.
- •Подобрать параметры га: размер популяции, вероятность скрещивания и мутации, количество поколений (если есть другие параметры, то и их тоже). Описать процесс подбора параметров.
- •Провести оптимизацию и визуализировать полученное решение. Графически отобразить решение. Например, траектория броска мяча или в виде таблицы показать расписание работы.
- •Построить график зависимости лучшей и средней приспособленности в зависимости от поколения.
Подобрать параметры га: размер популяции, вероятность скрещивания и мутации, количество поколений (если есть другие параметры, то и их тоже). Описать процесс подбора параметров.
Для подбора параметров был написан код. Сначала импортируются библиотеки random, numpy и deap. Затем создаются координаты городов и приоритеты доставки, определяются функции для расчета расстояний между городами, оценки маршрута (с учетом штрафа за превышение допустимого расстояния между пунктами) и выполнения самого алгоритма.
Функция compute_distance_matrix рассчитывает матрицу расстояний между всеми парами городов по их координатам, eval_route вычисляет длину маршрута с учетом штрафов за превышение допустимой длины перелета. Используется как функция оценки, run_ga запускает генетический алгоритм с заданными параметрами (скрещивание, мутация, штраф и др.), возвращает лучшее найденное решение и его оценку.
Основная функция – это функция hyperparameter_search, которая случайным образом перебирает наборы параметров: вероятность скрещивания и мутации, коэффициент штрафа и размер турнира. Для каждого набора параметров запускается алгоритм, и измеряется итоговая длина маршрута с учетом штрафов. Результаты всех запусков сравниваются, и выбирается лучший набор параметров, при котором маршрут оказался наиболее коротким. Реализация представлена в Листинге 2.2.1. Результат представлен в Листинге 2.2.2.
Листинг 2.2.1 – Подбор параметров ГА
import random from deap import base, creator, tools, algorithms import numpy as np
def compute_distance_matrix(coords): N = len(coords) D = np.zeros((N, N)) for i in range(N): for j in range(N): D[i][j] = np.hypot(coords[i][0] - coords[j][0], coords[i][1] - coords[j][1]) return D
def eval_route(individual, dist_matrix, Dmax=5.0, penalty_coef=10.0): total = 0 penalty = 0 for i in range(len(individual)): a = individual[i] b = individual[(i+1) % len(individual)] d = dist_matrix[a][b] total += d if d > Dmax: penalty += (d - Dmax) return total + penalty_coef * penalty,
def run_ga(coords, priorities, cxpb, mutpb, penalty_coef, tour_size, ngen=100, pop_size=200): dist_matrix = compute_distance_matrix(coords) N = len(coords)
if not hasattr(creator, 'FitnessMin'): creator.create("FitnessMin", base.Fitness, weights=(-1.0,)) if not hasattr(creator, 'Individual'): creator.create("Individual", list, fitness=creator.FitnessMin)
toolbox = base.Toolbox() toolbox.register("indices", random.sample, range(N), N) toolbox.register("individual", tools.initIterate, creator.Individual, toolbox.indices) toolbox.register("population", tools.initRepeat, list, toolbox.individual) toolbox.register("evaluate", eval_route, dist_matrix=dist_matrix, penalty_coef=penalty_coef) toolbox.register("mate", tools.cxOrdered) toolbox.register("mutate", tools.mutShuffleIndexes, indpb=0.2) toolbox.register("select", tools.selTournament, tournsize=tour_size)
pop = toolbox.population(n=pop_size) algorithms.eaSimple(pop, toolbox, cxpb=cxpb, mutpb=mutpb, ngen=ngen, verbose=False) best = tools.selBest(pop, 1)[0] return best, best.fitness.values[0]
def hyperparameter_search(coords, priorities, trials): best_score = float("inf") best_params = None for i in range(trials): params = { "cxpb": round(random.uniform(0.5, 1.0), 2), "mutpb": round(random.uniform(0.01, 0.5), 2), "penalty_coef": round(random.uniform(5.0, 30.0), 1), "tour_size": random.randint(2, 8) } try: best, score = run_ga(coords, priorities, cxpb=params["cxpb"], mutpb=params["mutpb"], penalty_coef=params["penalty_coef"], tour_size=params["tour_size"]) if score < best_score: best_score = score best_params = params except Exception: pass print(f"Оценка: {best_score:.2f}") print(f"Параметры: {best_params}") return best_params
N = 30 coords = [(random.uniform(0, 30), random.uniform(0, 30)) for _ in range(N)] priorities = [random.randint(1, 5) for _ in range(N)] best_params = hyperparameter_search(coords, priorities, 30) |
Листинг 2.2.2 – Лучшие параметры для ГА
Оценка: 249.15 Параметры: {'cxpb': 0.63, 'mutpb': 0.22, 'penalty_coef': 4.4, 'tour_size': 4} |
Выполнилось 30 запусков алгоритма с различными комбинациями параметров, случайно сгенерированными в допустимых диапазонах. Для каждого набора оценивалось качество финального решения. Лучшие параметры выбирались на основе минимального значения целевой функции. Исходя из этого, были подобраны следующие параметры: вероятность скрещивания – 0.63, вероятность мутации – 0.22, коэффициент штрафа – 4.4, размер турнира – 4. Количество поколений всегда равнялось 200 (эмпирическое наблюдение), а размер популяции всегда 100 (эмпирическое наблюдение).
