Python自然語言處理系列之模擬退火算法


1、基本概念

       模擬退火算法(Simulated Annealing,SA)是一種模擬固體降溫過程的最優化算法。其模擬的過程是首先將固體加溫至某一溫度,固體內部的粒子隨溫度上升慢慢變為無序的狀態,內能增大,然后讓其慢慢冷卻,溫度下降時,內部的粒子慢慢趨於有序,達到一種平衡態,最后達到常溫時成為基態,此時內能減為最小,算法模擬這樣一個過程期望能達到最優化的目的。

       模擬退火算法最早是由kirkpatrick等人應用於組合優化領域,它是基於Monte-Carlo迭代求解策略的一種隨機尋優算法。算法從某一較高溫度開始,不斷下降溫度參數,結合概率跳變性在解空間中隨機的尋找目標函數的全局最優解,算法的關鍵點是其能在降溫過程中達到局部最優解的情況下以一定的概率跳出局部最優解並最終趨於全局最優。模擬退火算法是一種通用的優化算法,理論上以概率1收斂於全局最優,在工程中有比較廣泛的應用,如VLSI、生成調度、控制工程、機器學習、神經網絡、信號處理等領域。

2、算法原理

       模擬退火算法分為三部分:初始解、解空間以及目標函數,分別對應物理退火過程中的初始溫度、降溫以及最終溫度。

      1)初始解:初始解釋算法迭代的起點,試驗表明,模擬退火算法是健壯的,即最終解的求得最優解並不十分依賴初始解的選取,從而可任意選擇一個初始解。當然,如果初始解選擇得當可以加快找到全局最優解。

      2)解空間:一般是離散的可行解的集合。

      3)目標函數:對優化目標的量化描述,是解空間到某個數集的一個映射,通常表示為若干優化目標的一個和式,應正確體現問題的整體優化要求且較易計算,當解空間包含不可行解時還應包括罰函數。

       算法從初始解或稱為初始狀態開始,在解空間中進行啟發式搜索(通常是隨機搜索的方式),最終搜索到最優的目標值。

       算法的基本過程如下:

  1. 初始化:設定初始溫度T,初始解狀態S,終止溫度T0;
  2. 降溫過程:如果T>T0,則循環執行3至6步;
  3. 在解空間中隨機搜索一個新解S’;
  4. 計算增量ΔE=E(S′)-E(S),其中C(S)為解S對應的目標函數值或稱為評價函數;
  5. 若ΔE<0則接受S′作為新的當前解,否則以概率exp(-ΔE/T)接受S′作為新的當前解;
  6. 如果滿足終止條件則輸出當前解作為最優解,結束程序。終止條件有兩種情況,一是溫度已經達到了最低溫度T0;二是在連續的取若干個新解都沒有跳出當前最優解

算法流程圖如下:

alt

3、退火方式

       模擬退火算法中,退火方式對算法有很大影響。如果溫度下降過慢,算法的收斂速度會大大降低。如果溫度下降過快,可能會丟失極值點。為了提高模擬退火算法的性能,許多學者提出了退火的各種方式,比較有代表性的有以下幾種:

1)alt

該方式的特點是溫度下降緩慢,算法收斂速度也較慢,但是最終達到全局最優的可能性是最高的

2)alt

式中a為可調參數,可以改善退火曲線的形態。其特點是高溫區溫度下降比較快,低溫區下降比較慢,這種退火方式主要期望在低溫區收斂到全局最優。

3)alt

式中a為可調參數,其特點是溫度下降很快,算法的收斂速度快,但是帶來的損失是可能不能充分的收斂到全局最優

以上三種退火方式各有優缺點以及適用的場景,需針對具體的應用進行選擇。

4、模擬退火算法在英文分詞中的應用

     (1)問題描述

       英文通常不需要分詞,因為其本身就是由一個個的英文單詞組成,我們考慮一種場景,比如在口語語言處理中,聽者必須將連續的語音流分割成單個的詞匯,考慮由機器進行分詞,這個問題就變得具有挑戰性了,考慮下面人為構造的例子,單詞邊界已被人為去除:

a:doyouseethekitty

b:seethedoggy

c:doyoulikethekitty

d:likethedoggy

       如果是由機器來識別單詞邊界,則需要找到一種算法來對每個句子進行分詞。我們可以給每個字符標注一個布爾值來指示這個字符后面是否有一個分詞標志,讓我們假設說話人會給語言學習者(機器)一個說話時的停頓,這往往是對應一個延長的暫停,分別對應了abcd四個句子塊。現在算法的任務就是對這個句子塊進行分詞,使得每個句子都能有對應的意思。

       經過處理后,四個句子變為如下的形式:

text = "doyouseethekittyseethedoggydoyoulikethekittylikethedoggy"

seg1= "0000000000000001000000000010000000000000000100000000000"

seg2= "0100100100100001001001000010100100010010000100010010000"

       其中seg1是初始解,seg2是全局最優的目標解,算法采用模擬退火算法通過若干輪迭代達到全局最優。

(2)模擬退火算法引入

  • 初始解:初始解即為上面提到的seg1串。
  • 解空間:解空間是離散的,分別對應的是串中每位為1的情況,每個塊(a、b、c、d)都有2的n次冪的分詞方法,n為塊的長度。
  • 目標函數:目標函數是一個打分函數,該打分函數能夠體現分詞的一個效果,也就是說分詞效果越接近全局最優,分數應越低或越高。

     模擬退火算法自身需要考慮三個與溫度相關的量:

  • 初始溫度:初始溫度可設為一個比較高的溫度,使得算法有足夠的時間收斂到全局最優
  • 降溫方式:降溫方式采用線性方式,T’=a*T,a是一個小於1的參數,可設為0.99,充分降溫,使得搜索解空間更加充分。
  • 終止溫度:終止溫度與初始溫度對應,當初始溫度降到終止溫度時,算法終止,因此終止溫度的選擇也與算法達到全局最優解密切相關

(3)算法設計

搜索解空間

        搜索解空間就是是尋找最大化目標函數值的0和1的模式,最好的分詞包括像“thekitty”這樣的“詞”,因為數據中沒有足夠的證據進一步分割這個詞。使用模擬退火算法的非確定性搜索即隨機搜索:一開始僅搜索短語分詞;隨機擾動0和1,它們與“溫度”成比例;每次迭代溫度都會降低,擾動邊界會減少

目標函數或代價函數

       目標函數是一個打分函數,我們將基於詞典的大小和從詞典中重構源文本所需的信息量盡力優化它的值。

alt

       給定一個假設的源文本的分詞(左),推導出一個詞典和推導表,它能讓源文本重構,然后合計每個詞項(包括邊界標志)與推導表的字符數,作為分詞質量的得分;得分值越小表明分詞越好。

       如上圖示的一種分詞情況,目標得分包括兩個部分,一個分詞得分LEXICON,一個是分塊得分DERIVATION。LEXICON對分好的每個唯一的詞進行算分,分數即為單詞長度加上邊界1,如doyou的分詞得分為單詞長度5加上邊界1即為6,其他詞計算方法類似;分塊得分就是買個塊包含的單詞數量,如第一個1|2|4|6,其得分為4,依次類推,最終得到分詞得分為33,分塊得分為14,兩者相加即為總得目標得分,該目標得分越小則分詞效果就越好,也就越接近我們人工識別的目標。

(3)算法偽代碼

        @text:待分詞文本

        @segs:初始解,為01串

        @iterations:每個溫度的迭代次數,目的是在在每次降溫時都能找到一個當前最優的解,

這個量是當目標達到一個局部最優時,能夠使得算法有一定的概率跳出當前局部最優解,是模擬退火算法中以一定概率接受較差解的一種實現方式,隨着溫度的降低,這種概率會減小,具體實現是flip_n函數,其跳變的位數與溫度正相關。

 @a:退火因子

        string anneal(text, segs, iterations, a)

         T=float(length(segs));

         while T > T0

                   score=evaluate(text, segs)

                            best_segs=segs

                            for i=1 to iterations

//flip_n是隨機選擇n位位進行跳變,這里n為int(round(T)),其與當前溫//度相關,溫度下降時,跳變的位數會減小,具體實現原理是保證溫度下//降時,解跳變的概率會減小,最后返回跳變后的串

                                     guess = flip_n(segs, int(round(T)))

                                     //evalue即是我們上面討論的目標函數或代價函數

                                     score = evalue(text, guess)

                                     if score < best

                                               best = score

                                               best_segs=guess

                            score = best

                            segs = best_segs

                            T = T*a//降溫

                            //打印每一步的優化結果

                            print evalue(text, segs), segment(text, segs)

經過程序實際運行,打印過程為,最左邊一列是其對應分數

60     ['doyouseetheki', 'tty', 'see', 'thedoggy', 'doyouliketh', 'ekittylike', 'thedoggy']

58     ['doy', 'ouseetheki', 'ttysee', 'thedoggy', 'doy', 'o', 'ulikethekittylike', 'thedoggy']

56     ['doyou', 'seetheki', 'ttysee', 'thedoggy', 'doyou', 'liketh', 'ekittylike', 'thedoggy']

54     ['doyou', 'seethekit', 'tysee', 'thedoggy', 'doyou', 'likethekittylike', 'thedoggy']

53     ['doyou', 'seethekit', 'tysee', 'thedoggy', 'doyou', 'like', 'thekitty', 'like', 'thedoggy']

51     ['doyou', 'seethekittysee', 'thedoggy', 'doyou', 'like', 'thekitty', 'like', 'thedoggy']

42     ['doyou', 'see', 'thekitty', 'see', 'thedoggy', 'doyou', 'like', 'thekitty', 'like', 'thedoggy']

42分是最優結果,對應全局最優的01串是:

'0000100100000001001000000010000100010000000100010000000'


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM