O que é o PSO com inércia?
O PSO com inércia é uma evolução do PSO clássico que introduz um fator de amortecimento. Esse fator, chamado de peso de inércia (w), controla a influência da velocidade anterior. Ele foi proposto por Shi e Eberhart em 1998 para melhorar o equilíbrio exploratório. Diferentemente da versão clássica, w pode ser constante ou variar ao longo do tempo. Uma estratégia comum é reduzir w linearmente de 0.9 para 0.4 durante a execução. Isso permite exploração global no início e explotação local no final. A equação de velocidade torna-se: v = w*v + c₁*r₁*(pbest – x) + c₂*r₂*(gbest – x). O PSO com inércia é atualmente a versão mais usada em aplicações práticas. Ela oferece melhor desempenho em funções multimodais e com ruído.
Características fundamentais do PSO com inércia
O PSO com inércia possui três características distintas que o definem. Primeira, o peso w pode ser fixo (ex.: 0.7) ou dinâmico (decrescente). A inércia dinâmica é frequentemente linear: w(t) = w_max – (w_max – w_min)*(t/T). Segunda, a velocidade ainda é limitada por vmax para evitar instabilidades. Terceira, os coeficientes c₁ e c₂ permanecem constantes, geralmente iguais a 1.5. A inércia atua como um “momento” que suaviza as mudanças de direção. Isso evita oscilações bruscas e melhora a convergência para o ótimo. Além disso, a inércia reduz a dependência de condições iniciais aleatórias. O PSO com inércia é mais robusto e tolerante a erros de parametrização.
Vantagens e aplicações típicas
A principal vantagem é o controle explícito entre exploração e explotação. Com w alto, as partículas percorrem grandes regiões do espaço de busca. Com w baixo, elas refinam a solução localmente com alta precisão. Isso torna o PSO com inércia eficaz para problemas com muitos mínimos locais. Ele é amplamente usado em redes neurais, controle de processos e design ótimo. Além disso, a inércia dinâmica dispensa ajustes manuais finos. Contudo, a escolha da taxa de decaimento ainda requer alguma experimentação.
O PSO com inércia foi uma resposta às limitações da versão clássica. Estudos mostraram que w > 1 pode causar divergência do enxame. Por outro lado, w < 0.5 leva a convergência prematura e estagnação. A faixa recomendada é entre 0.4 e 0.9 para a maioria dos problemas. A redução linear é a mais popular por sua simplicidade e eficácia. Ela permite que o enxame explore amplamente no início da execução. Nas últimas iterações, as partículas se concentram ao redor do gbest. Esse comportamento mimetiza o resfriamento simulado em otimização. O PSO com inércia também pode ser combinado com técnicas de reinicialização. Por exemplo, quando o enxame estagna, w é temporariamente aumentado. Isso reintroduz diversidade sem perder as melhores soluções encontradas. A inércia também facilita a adaptação a funções com escalas diferentes. Cada dimensão pode ter seu próprio w em variantes mais avançadas. Assim, o PSO com inércia é versátil e amplamente adotado na indústria.
Um exemplo clássico é minimizar a função de Griewank em 2 dimensões. Ela tem muitos mínimos locais, mas um mínimo global em (0,0). O PSO com inércia dinâmica encontra esse ótimo com alta confiabilidade. A redução de w permite escapar de vales falsos nas primeiras iterações.
Enunciado do exemplo clássico
Implemente o PSO com inércia linearmente decrescente para minimizar a função de Griewank: f(x,y) = (x²+y²)/4000 – cos(x)*cos(y/√2) + 1, com x,y ∈ [-10, 10]. Use 30 partículas, 300 iterações, w de 0.9 a 0.4, c₁=c₂=1.5, vmax=2. Armazene o melhor fitness e a posição global a cada iteração. Plote a curva de convergência e a trajetória do gbest com contornos.
|
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 |
import numpy as np import matplotlib.pyplot as plt # Função de Griewank (minimização) def griewank(x, y): return (x**2 + y**2)/4000 - np.cos(x) * np.cos(y / np.sqrt(2)) + 1 # Parâmetros num_particulas = 30 iteracoes = 300 w_max = 0.9 w_min = 0.4 c1 = 1.5 c2 = 1.5 vmax = 2.0 limites = [-10, 10] dim = 2 # Inicialização posicoes = np.random.uniform(limites[0], limites[1], (num_particulas, dim)) velocidades = np.random.uniform(-vmax, vmax, (num_particulas, dim)) pbest_pos = posicoes.copy() pbest_fit = np.array([griewank(p[0], p[1]) for p in posicoes]) gbest_idx = np.argmin(pbest_fit) gbest_pos = pbest_pos[gbest_idx].copy() gbest_fit = pbest_fit[gbest_idx] # Históricos melhor_fit_hist = [gbest_fit] melhor_pos_hist = [gbest_pos.copy()] for it in range(iteracoes): # Inércia decrescente linearmente w = w_max - (w_max - w_min) * (it / iteracoes) for i in range(num_particulas): r1, r2 = np.random.random(dim), np.random.random(dim) velocidades[i] = (w * velocidades[i] + c1 * r1 * (pbest_pos[i] - posicoes[i]) + c2 * r2 * (gbest_pos - posicoes[i])) velocidades[i] = np.clip(velocidades[i], -vmax, vmax) posicoes[i] += velocidades[i] posicoes[i] = np.clip(posicoes[i], limites[0], limites[1]) fit_atual = np.array([griewank(p[0], p[1]) for p in posicoes]) for i in range(num_particulas): if fit_atual[i] < pbest_fit[i]: pbest_fit[i] = fit_atual[i] pbest_pos[i] = posicoes[i].copy() if np.min(fit_atual) < gbest_fit: gbest_idx = np.argmin(fit_atual) gbest_fit = fit_atual[gbest_idx] gbest_pos = posicoes[gbest_idx].copy() melhor_fit_hist.append(gbest_fit) melhor_pos_hist.append(gbest_pos.copy()) print(f"Melhor fitness: {gbest_fit:.6f}") print(f"Melhor posição: x={gbest_pos[0]:.6f}, y={gbest_pos[1]:.6f}") # Gráficos plt.figure(figsize=(12, 5)) plt.subplot(1, 2, 1) plt.semilogy(melhor_fit_hist, 'g-', linewidth=2) plt.title('PSO com Inércia Decrescente - Griewank') plt.xlabel('Iteração') plt.ylabel('Melhor fitness (log)') plt.grid(True) plt.subplot(1, 2, 2) x_vals = np.linspace(limites[0], limites[1], 200) y_vals = np.linspace(limites[0], limites[1], 200) X, Y = np.meshgrid(x_vals, y_vals) Z = griewank(X, Y) plt.contourf(X, Y, Z, levels=50, cmap='inferno', alpha=0.7) plt.colorbar(label='f(x,y)') gbest_traj = np.array(melhor_pos_hist) plt.plot(gbest_traj[:,0], gbest_traj[:,1], 'w-', linewidth=1.5, alpha=0.8, label='Trajetória gbest') plt.scatter(gbest_traj[0,0], gbest_traj[0,1], color='lime', s=80, label='Início') plt.scatter(gbest_traj[-1,0], gbest_traj[-1,1], color='red', s=100, label='Final') plt.scatter(0, 0, color='white', marker='*', s=200, label='Ótimo (0,0)') plt.title('Trajetória com Inércia Dinâmica') plt.xlabel('x') plt.ylabel('y') plt.legend() plt.grid(True) plt.tight_layout() plt.show() |
Este código implementa o PSO com inércia linearmente decrescente. A curva de convergência mostra uma queda suave e consistente do erro. A trajetória do gbest revela exploração ampla no início e refinamento no final. A inércia dinâmica permite escapar de mínimos locais da função Griewank. Para iniciantes, este exemplo demonstra o poder do controle adaptativo. O PSO com inércia é, portanto, uma ferramenta madura e confiável.