1. 程式人生 > >【尋優演算法】量子粒子群演算法(QPSO) 引數尋優的python實現

【尋優演算法】量子粒子群演算法(QPSO) 引數尋優的python實現

【尋優演算法】量子粒子群演算法(QPSO) 引數尋優的python實現

一、粒子群演算法的缺點

本人之前的博文(參考資料【1】)已經詳細介紹了PSO演算法,學習本博文前需要先學習PSO演算法。

PSO演算法的缺點:
1、需要設定的引數(慣性因子 w w

,區域性學習因子 c 1 {c_1} 和全域性學習因子 c 2 {c_2}
)太多,不利於找到待優化模型的最優引數。
2、粒子位置變化缺少隨機性,容易陷入區域性最優的陷阱。

二、量子粒子群演算法

量子粒子群優化(Quantum Particle Swarm Optimization,QPSO)演算法取消了粒子的移動方向屬性,粒子位置的更新跟該粒子之前的運動沒有任何關係,這樣就增加了粒子位置的隨機性(參考資料【2】)。
量子粒子群演算法中引入的新名詞:
mbest:表示pbest的平均值,即平均的粒子歷史最好位置。
量子粒子群演算法的粒子更新步驟:
步驟一:計算mbest

M

b e s t = 1 M i = 1 M p b e s t _ i {M_{best}} = \frac{1}{M}\sum\limits_{i = 1}^M {{p_{best\_i}}}

其中 M M 表示粒子群的大小, p b e s t _ i {p_{best\_i}} 表示當前迭代中的第 i i p b e s t pbest

步驟二:粒子位置更新

P i = ϕ p b e s t _ i + ( 1 ϕ ) g b e s t {P_i} = \phi \cdot {p_{best\_i}} + (1 - \phi )gbest

其中 g b e s t gbest 表示當前全域性最優粒子, P i {P_i} 用於第 i i 個粒子位置的更新。
粒子位置更新公式為:

x i = P i ± α M b e s t x i ln ( 1 u ) {x_i} = {P_i} \pm \alpha \left| {{M_{best}} - {x_i}} \right|\ln \left( {\frac{1}{u}} \right)

其中 x i {x_i} 表示第 i i 個粒子的位置, α \alpha 為創新引數, ϕ \phi u u 0 , 1 (0,1) 上的均勻分佈數值。取 + + - 的概率為0.5。

由上所示,QPSO演算法中只有一個創新引數 α \alpha 設定,一般 α \alpha 不大於1。

三、QPSO演算法的python實現

完整python程式碼和樣本地址:https://github.com/shiluqiang/QPSO_python
本博文以非線性SVM為待優化模型,待優化引數為正則化引數 C C 和核引數 σ \sigma ,適應度函式值為3-fold交叉驗證平均值。

## 2. QPSO演算法
class QPSO(object):
    def __init__(self,particle_num,particle_dim,alpha,iter_num,max_value,min_value):
        '''定義類引數
        particle_num(int):粒子群大小
        particle_dim(int):粒子維度,對應待尋優引數的個數
        alpha(float):控制係數
        iter_num(int):最大迭代次數
        max_value(float):引數的最大值
        min_value(float):引數的最小值
        '''
        self.particle_num = particle_num
        self.particle_dim = particle_dim
        self.iter_num = iter_num
        self.alpha = alpha
        self.max_value = max_value
        self.min_value = min_value

### 2.1 粒子群初始化
    def swarm_origin(self):
        '''初始化粒子群中的粒子位置
        input:self(object):QPSO類
        output:particle_loc(list):粒子群位置列表
        '''
        particle_loc = []
        for i in range(self.particle_num):
            tmp1 = []
            for j in range(self.particle_dim):
                a = random.random()
                tmp1.append(a * (self.max_value - self.min_value) + self.min_value)
            particle_loc.append(tmp1)
        
        return particle_loc

### 2.2 計算適應度函式數值列表
    def fitness(self,particle_loc):
        '''計算適應度函式值
        input:self(object):PSOparticle_loc(list):粒子群位置列表
        output:fitness_value(list):適應度函式值列表
        '''
        fitness_value = []
        ### 1.適應度函式為RBF_SVM3_fold交叉校驗平均值
        for i in range(self.particle_num):
            rbf_svm = svm.SVC(kernel = 'rbf', C = particle_loc[i][0], gamma = particle_loc[i][1])
            cv_scores = cross_validation.cross_val_score(rbf_svm,trainX,trainY,cv =3,scoring = 'accuracy')
            fitness_value.append(cv_scores.mean())
        ### 2. 當前粒子群最優適應度函式值和對應的引數
        current_fitness = 0.0
        current_parameter = []
        for i in range(self.particle_num):
            if current_fitness < fitness_value[i]:
                current_fitness = fitness_value[i]
                current_parameter = particle_loc[i]

        return fitness_value,current_fitness,current_parameter

### 2.3 粒子位置更新    
    def updata(self,particle_loc,gbest_parameter,pbest_parameters):
        '''粒子位置更新
        input:self(object):QPSOparticle_loc(list):粒子群位置列表
              gbest_parameter(list):全域性最優引數
              pbest_parameters(list):每個粒子的歷史最優值
        output:particle_loc(list):新的粒子群位置列表
        '''
        Pbest_list = pbest_parameters
        #### 2.3.1 計算mbest
        mbest = []
        total = []
        for l in range(self.particle_dim):
            total.append(0.0)
        total = np.array(total)
        
        for i in range(self.particle_num):
            total += np.array(Pbest_list[i])
        for j in range(self.particle_dim):
            mbest.append(list(total)[j] / self.particle_num)
        
        #### 2.3.2 位置更新
        ##### Pbest_list更新
        for i in range(self.particle_num):
            a = random.uniform(0,1)
            Pbest_list[i] = list(np.array([x * a for x in Pbest_list[i]]) + np.array([y * (1 - a) for y in gbest_parameter]))
        ##### particle_loc更新
        for j in range(self.particle_num):
            mbest_x = []  ## 儲存mbest與粒子位置差的絕對值
            for m in range(self.particle_dim):
                mbest_x.append(abs(mbest[m] - particle_loc[j][m]))
            u = random.uniform(0,1)
            if random.random() > 0.5:
                particle_loc[j] = list(np.array(Pbest_list[j]) + np.array([self.alpha * math.log(1 / u) * x for x in mbest_x]))
            else:
                particle_loc[j] = list(np.array(Pbest_list[j]) - np.array([self.alpha * math.log(1 / u) * x for x in mbest_x]))
                
        #### 2.3.3 將更新後的量子位置引數固定在[min_value,max_value]內 
        ### 每個引數的取值列表
        parameter_list = []
        for i in range(self.particle_dim):
            tmp1 = []
            for j in range(self.particle_num):
                tmp1.append(particle_loc[j][i])
            parameter_list.append(tmp1)
        ### 每個引數取值的最大值、最小值、平均值   
        value = []
        for i in range(self.particle_dim):
            tmp2 = []
            tmp2.append(max(parameter_list[i]))
            tmp2.append(min(parameter_list[i]))
            value.append(tmp2)
        
        for i in range(self.particle_num):
            for j in range(self.particle_dim):
                particle_loc[i][j] = (particle_loc[i][j] - value[j][1])/(value[j][0] - value[j][1]) * (self.max_value - self.min_value) + self.min_value
                
        return particle_loc

## 2.4 畫出適應度函式值變化圖
    def plot(self,results):
        '''畫圖
        '''
        X = []
        Y = []
        for i in range(self.iter_num):
            X.append(i + 1)
            Y.append(results[i])
        plt.plot(X,Y)
        plt.xlabel('Number of iteration',size = 15)
        plt.ylabel('Value of CV',size = 15)
        plt.