最優化算法----模擬退火+Python實現

基本模型

模擬退貨算法可以分解爲解空間、目標函數和初始解三部分

基本思想

求一個函數的最優解可以通過貪心算法獲得其最優解,但有可能是局部最有解,而不是全局最優解。爲了解決這一問題,產生了模擬退火算法,該算法是在搜索的過程中加入了隨機的因素,以一定的概率接受比當前解要差的解,因此有可能會跳出這個局部最優解,達到全局最優解。

基本步驟

  1. 初始化:初始溫度 TT, 溫度變化率 ΔT\Delta T (通常取值0.950.990.95-0.99),初始解狀態 SS,每個TT值的迭代次數 LL
  2. k=1,...,Lk=1, ..., L 做第 3 至第 6 步;
  3. 產生新解 SS'
  4. 計算增量 Δt=C(S)C(S)\Delta t' = C(S') - C(S),其中 C(S)C(S) 爲評價函數;
  5. Δt<0\Delta t' < 0 則接受 SS' 作爲新的當前解,否則以概率 MetropolisMetropolis 準則接受 SS'作爲當前解;
  6. 如果滿足終止條件則輸出當前解作爲最優解,結束程序;
  7. TT 根據 ΔT\Delta T 逐漸減少,且 T0T \to 0,然後轉向第二步。

Metropolis準則
P={1,E(xnew)<E(xold)exp(E(xnew)E(xold)T,E(xnew)E(xold) P = \begin{cases} 1&, {E(x_{new}) < E(x_{old})}\\ exp(-\frac{E(x_{new}) - E(x_{old})}{T}&, {E(x_{new}) \geq E(x_{old}}) \end{cases}
其中,T爲當前的溫度,在 E(xnew)E(xold)E(x_{new}) \geq E(x_{old}) 時,求出的 pp(0,1)(0, 1) 之間,以此概率接受比當前解要差的解。

參數設置

初始溫度:初始溫度的確定可以隨機產生數據來粗略的估計一下,比如可以先進行100個迭代,計算出目標函數的平均差值或者最大差值,再根據你希望的初始溫度下由當前解轉換爲較差的解的概率和Metropolis準則計算出初始溫度。

最小溫度:可以設置的很小,進行很多次的迭代,找到全局最優解。

溫度變化率:一般設置爲 0.950.990.95 - 0.99 之間的值,一般使用 T(i+1)=ΔTT(i)T(i + 1) = \Delta T * T(i) 來衰減溫度,當然也可以根據自己想要的衰減速率選取合適的公式。

目標函數:要求解的函數。

生成新解:可以在當前解的基礎上進行部分或者全部值的改動,根據自己解的需求限定當前解的範圍。

Python實現(部分)

# -*- coding: utf-8 -*-
import math
import random

ITERS = 100             # 每個溫度下的迭代次數
T = 100                 # 初始溫度
T_min = 0.002           # 溫度最小值
delta_t = 0.98          # 溫度變化率


class SA:
    '''
    求最小值
    '''
    def __init__(self):
        self.t = T
        self.iters = ITERS
        self.t_min = T_min
        self.delta_t = delta_t

    def sa(self, fun):
        '''
        模擬退火算法
        :param fun: 目標函數
        :return:
        '''
        x_old = self._init_x()
        y_old = fun(x_old)
        while self.t > self.t_min:
            for i in range(self.iters):
                x_new = self._update_x(x_old)
                y_new = fun(x_new)
                loss = y_new - y_old
                if loss <= 0:               # 替換比當前解好的解
                    x_old = x_new
                    y_old = y_new
                else:
                    random_p = random.random()
                    if self.metropolis(loss) > random_p:    # 以一定概率替換比當前解差的解
                        x_old = x_new
                        y_old = y_new
            # 是否滿足條件, 滿足則結束, 不滿足則更新溫度繼續
            self.t *= self. delta_t
        # 最終保存或者輸出最優解
        print("x {}, y {}".format(x_old, y_old))

    def metropolis(self, loss):
        return math.e ** (loss / self.t)

    def _update_x(self, x_old):
        '''
        生成新解
        :return:
        '''
        pass

    def _init_x(self):
        '''
        設置初始解
        :return:
        '''
        pass
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章