7. 실용 예제
이 장에서는 이전 장의 지식을 적용하는 방법을 보여주는 여러 완전한 실용 예제를 제시합니다. 처음부터 최적화 프로젝트를 구축하고 EvoX를 다른 도구와 통합하는 방법을 보여줍니다. 이 예제들은 실제 시나리오에서 EvoX를 적용하는 데 도움이 되도록 다양한 문제 유형을 다룹니다.
예제 1: 단일 목적 최적화
문제: 고전적인 Rastrigin 함수 최적화:
f(\mathbf{x}) = 10 d + \sum_{i=1}^{d}[x_i^2 - 10 \cos{(2\pi x_i)}],
여기서 $\mathbf{x} \in \mathbb{R}^d$이고 $d$는 차원입니다. 전역 최적값은 원점에서 0입니다. 이 함수는 매우 다봉적이어서 전역 최적화 알고리즘을 테스트하는 데 이상적입니다. 다음은 Rastrigin 함수의 그래프입니다.
:alt: Rastrigin 함수의 그래프
:figwidth: 70%
:align: center
Rastrigin 함수
이 예제에서는 입자 군집 최적화(PSO) 알고리즘을 사용하여 10차원 Rastrigin 함수를 최적화합니다.
단계 1: 설정
2장에서 설명한 대로 EvoX 환경을 구성했다고 가정합니다.
단계 2: 워크플로우 설정
Python 스크립트 opt_rastrigin_10.py를 생성하세요:
import torch
from evox.algorithms.so.pso_variants import PSO
from evox.problems.numerical.basic import Rastrigin
from evox.workflows import StdWorkflow, EvalMonitor
PSO 알고리즘을 정의하세요:
dim = 10
algo = PSO(
pop_size=50,
lb=-32 * torch.ones(dim),
ub=32 * torch.ones(dim)
)
문제와 워크플로우를 설정하세요:
prob = Rastrigin()
monitor = EvalMonitor()
workflow = StdWorkflow(
algorithm=algo,
problem=prob,
monitor=monitor
)
단계 3: 최적화 실행
workflow.init_step()
for iter in range(501):
workflow.step()
if iter % 100 == 0:
current_best_fitness = monitor.get_best_fitness().item()
print(f"Iter {iter}, Best Fitness: {current_best_fitness}")
print(f"Final Best Solution: {monitor.get_best_solution()}")
샘플 출력:
Iter 0, Best Fitness: 1398.625
Iter 100, Best Fitness: 11.608497619628906
Iter 200, Best Fitness: 2.5700759887695312
Iter 300, Best Fitness: 1.9909820556640625
Iter 400, Best Fitness: 1.9899139404296875
Iter 500, Best Fitness: 0.9976348876953125
Final Best Solution: tensor([...])
PSO 알고리즘은 예상대로 원점에 가까운 거의 최적의 솔루션을 찾습니다.
예제 2: 다목적 최적화
문제: 두 가지 목적을 최소화:
f_1(x) = x^2, \quad
f_2(x) = (x - 2)^2
파레토 프론트는 $x = 0$($f_1$에 최적)과 $x = 2$($f_2$에 최적) 사이에 있습니다.
단계 1: 환경 설정
NSGA-II 지원이 포함된 EvoX가 설치되어 있는지 확인하세요.
단계 2: 사용자 정의 문제 정의
EvoX에는 많은 내장 다목적 테스트 문제가 있지만, 이 예제에서는 두 가지 목적을 최적화하기 위한 사용자 정의 문제를 정의합니다:
import torch
import numpy as np
import matplotlib.pyplot as plt
from evox.algorithms import NSGA2
from evox.workflows import StdWorkflow, EvalMonitor
# evox 핵심 클래스 임포트, 자세한 내용은 5장 참조
from evox.core import Problem
class TwoObjectiveProblem(Problem):
def __init__(
self,
d: int = 1,
m: int = 2,
):
super().__init__()
self.d = d
self.m = m
def evaluate(self, X: torch.Tensor) -> torch.Tensor:
x = X[:, 0]
f_1 = x ** 2
f_2 = (x - 2) ** 2
return torch.stack([f_1, f_2], dim=1)
# 선택 사항: 파레토 프론트 함수 정의
def pf(self) -> torch.Tensor:
pass
단계 3: 알고리즘 및 워크플로우 정의
from evox.algorithms import NSGA2
from evox.workflows import StdWorkflow, EvalMonitor
prob = TwoObjectiveProblem()
torch.set_default_device("cuda:0")
algo = NSGA2(
pop_size=50,
n_objs=2,
lb=-5 * torch.ones(1),
ub=5 * torch.ones(1),
device=torch.device("cuda"),
)
monitor = EvalMonitor()
workflow = StdWorkflow(algo, prob, monitor)
단계 4: 최적화 및 시각화
workflow.init_step()
for i in range(100):
workflow.step()
data = algo.fit.cpu().numpy()
import numpy as np
import matplotlib.pyplot as plt
x_vals = np.linspace(0, 2, 400)
pf_f1 = x_vals ** 2
pf_f2 = (x_vals - 2) ** 2
plt.figure(figsize=(8, 6))
plt.scatter(data[:, 0], data[:, 1], c='blue', label='Optimized Population', alpha=0.7)
plt.plot(pf_f1, pf_f2, 'r-', linewidth=2, label='Pareto Front')
plt.xlabel("f1")
plt.ylabel("f2")
plt.title("NSGA-II on Bi-objective Problem")
plt.legend()
plt.grid(True)
plt.show()
Matplotlib를 사용하여 결과를 시각화할 수 있습니다. 파란색 점은 최적화된 개체군을 나타내고, 빨간색 선은 파레토 프론트를 보여줍니다.
:alt: NSGA-II 개체군의 그래프
:figwidth: 70%
:align: center
최적화 후 NSGA-II 개체군의 그래프
Jupyter Notebook에서는 EvoX의 내장 플로팅 기능을 사용하여 최적화 과정을 시각화하고 세대에 걸쳐 개체군이 어떻게 진화하는지 모니터링할 수 있습니다.
monitor.plot()
예제 3: 하이퍼파라미터 최적화 (HPO)
문제: 유방암 데이터셋에서 로지스틱 회귀 분류기의 C와 max_iter를 조정하여 검증 정확도를 최대화합니다.
단계 1: 데이터 및 모델 로드
import torch
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from evox.core import Problem
X, y = load_breast_cancer(return_X_y=True)
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)
scaler = StandardScaler().fit(X_train)
X_train = scaler.transform(X_train)
X_val = scaler.transform(X_val)
단계 2: 문제 정의
class HyperParamOptProblem(Problem):
def __init__(self):
super().__init__()
def evaluate(self, pop):
pop = pop.detach().cpu().numpy()
objs = []
for C_val, max_iter_val in pop:
C_val = float(max(1e-3, C_val))
max_iter_val = int(max(50, max_iter_val))
model = LogisticRegression(C=C_val, max_iter=max_iter_val, solver='liblinear')
model.fit(X_train, y_train)
acc = model.score(X_val, y_val)
objs.append(1 - acc) # 오류율
return torch.tensor(objs)
단계 3: 워크플로우 설정
from evox.algorithms.so.es_variants import CMAES
from evox.workflows import EvalMonitor, StdWorkflow
prob = HyperParamOptProblem()
init_params = torch.tensor([1.0, 100.0])
print("초기 오류율:", prob.evaluate(init_params.unsqueeze(0)).item())
algo = CMAES(
mean_init=init_params,
sigma=1.0,
)
monitor = EvalMonitor()
workflow = StdWorkflow(algo, prob, monitor)
단계 4: 최적화
workflow.init_step()
for _ in range(100):
workflow.step()
best_params = monitor.get_best_solution()
best_error = prob.evaluate(best_params.unsqueeze(0)).item()
print("최적화된 오류율:", best_error)
샘플 출력:
초기 오류율: 0.0263
최적화된 오류율: 0.0088
몇 줄의 코드만으로 EvoX는 지루한 하이퍼파라미터 조정의 시행착오를 자동화합니다.
이러한 실용 예제는 수학적 테스트 함수에서 머신러닝 워크플로우에 이르기까지 다양한 도메인에서 EvoX를 효과적으로 적용할 수 있는 방법을 보여줍니다. 기본 구조인 알고리즘 + 문제 + 모니터 + 워크플로우에 익숙해지면 거의 모든 최적화 작업에 맞게 EvoX를 적용할 수 있습니다.