LasyOpticalDesigner0.1.0開發者日誌(八)優化器(壹)

優化器

光學系統優化有局部優化和全局優化以及介乎二者之間的優化方法。
由於全局優化的算法過於複雜
這裏只介紹前後兩種。

局部優化方法

光學系統局部優化方法主要是從某個起始點處出發,尋找最近的局部評價函數最小點,其原理就是利用梯度或者偏導數確定方向然後利用貪心策略進行搜索。衆所周知,梯度是函數值增加最快的方向(最大方向導數),所以梯度方向的反方向就是函數下降的方向:
除去傳統的牛頓法,阻尼牛頓法,最速下降法等等。
也可以使用adm,admW,sgd,rmsprop等算法。這些算法網上已經有無數的詳細說明,這裏就不再提

建立一個簡單的類似光學傳播的模型

class TestModel(tf.keras.Model):
    
    def __init__(self):
        super(TestModel,self).__init__()
        self.de_layers = []
    
    def get_layer(self,layer):
        self.de_layers.append(layer)
    
    def call(self,x,y):
        for layer in self.de_layers:
            x , y = layer(x,y)
        return x,y

建立層

class TestLayer(tf.keras.layers.Layer):
    def __init__(self,w1,w2,w3,w4):
        super(TestLayer,self).__init__()
        self.w1 = tf.Variable(w1,dtype = tf.float32,trainable = True)
        self.w2 = tf.Variable(w2,dtype = tf.float32,trainable = True)
        self.w3 = tf.Variable(w3,dtype = tf.float32,trainable = True)
        self.w4 = tf.Variable(w4,dtype = tf.float32,trainable = True)

    def call(self,r,sita):      
        n_r =self.w1 * (r**2+sita**2)**0.5- self.w2*(sita * r) + self.w4*r*tf.cos(sita) 
        n_sita = self.w2*(r**2 - sita**2)**0.5 - self.w3*(sita + r) + self.w4*r*tf.sin(sita)
        return n_r,n_sita

執行器

class MyManagers:
    def __init__(self,model,number,af):
        self.testmodel = model
        self.opt = tf.keras.optimizers.RMSprop()
        # 這裏也可以用sgd,adm等等或者自定義的其他優化器這裏用RMSprop

局部優化

    @tf.function
    def opt_manager(self):
        for i in range(200):# 200 可以自定義
            r,sita = self.testmodel(self.r,self.sita)
            loss = tf.reduce_sum(tf.square(r) + tf.square(sita))
            # 用歐氏距離平方做評價函數
            g = tf.gradients(loss,self.testmodel.trainable_variables)
            #梯度
            self.opt.apply_gradients(grads_and_vars = zip(g,self.testmodel.trainable_variables))
            # 優化
        return self.testmodel.trainable_variables,loss

錘子優化算法(錘形的翻譯有一定的問題),(hammer)——半全局方法

這種算法在zemax的操作說明中並沒有詳細的描述,相關的文獻也非常的稀少。操作說明中僅僅是介紹了它的效果。通過不斷的跳出或者避開局部最小點,儘可能的達到更小的評價函數點
——錘子優化法之所以叫這個名字,猜測是由於使用各種各樣的方式使得評價函數儘可能下降的方法,好比鍛造時用榔頭敲擊金屬
這樣的策略有很多

  1. 模擬退火的方法
    在優化過程中依照某種概率選擇優化的步長該步長與評價函數有關(溫度下降個概率與當前溫度有關)
    在這裏可以用評價函數loss與梯度g的範數的比值作爲判別數
    af = loss/g當loss很大而g的二範數比較小,說明這個點是局部最小點
    這樣的話優化使用其他的更長的步長以跳出這個局部最小點。
	@tf.function
    def opt_manager_hummer(self,aita=1.0,e=0.0,d=0.025):
        r,sita = self.testmodel(self.r,self.sita)
        loss = tf.reduce_sum(tf.square(r) + tf.square(sita))
        g= tf.gradients(loss,self.testmodel.trainable_variables)
        def body1():
        	# 使用一般的 優化器
            for j in range(10):
                self.opt.apply_gradients(grads_and_vars = zip(g,self.testmodel.trainable_variables))    
        def body2():
        	# 使用第二個優化器 步長比較長讓函數變得鬆弛
            self.opt1.apply_gradients(grads_and_vars = zip(g,self.testmodel.trainable_variables))
        for i in range(100):
            r,sita = self.testmodel(self.r,self.sita)
            loss = tf.reduce_sum(tf.square(r) + tf.square(sita))
            g= tf.gradients(loss,self.testmodel.trainable_variables)
            base = aita*tf.exp(-tf.reduce_sum(tf.square(g))/loss) 
            aim = tf.random.normal([],aita*e,d,dtype = tf.float32)
            q = base-aim # it must unstable that q is bigger
            tf.cond(
                q*10 < self.af,
                body1,
                body2
            )
            tf.print(i)
        return self.testmodel.trainable_variables,loss
  1. 遺傳算法的一個變種
    將被判斷爲局部最小點的點收集起來,排除掉他們然後朝着剩下的點進行搜索
    具體的方法有:當收集某一個點時,到這個點的距離的某個反相關的函數將加入到評價函數。然後利用梯度下降的方法迫使搜索方向遠離這個點
    參考代碼:
    @tf.function
    def opt_manager_dec(self,aita=1.0,e=0.0,d=0.025):
        points = []
        r,sita = self.testmodel(self.r,self.sita)
        loss = tf.reduce_sum(tf.square(r) + tf.square(sita))
        g = tf.gradients(loss,self.testmodel.trainable_variables)
        def add_point_opt():
            temp = self.testmodel.trainable_variables
            points.append(temp)
            loss = tf.reduce_sum(tf.square(r) + tf.square(sita))+get_loss() 
            g = tf.gradients(loss,self.testmodel.trainable_variables)
            self.opt.apply_gradients(grads_and_vars = zip(g,self.testmodel.trainable_variables))         
        def commen_opt():
            loss = tf.reduce_sum(tf.square(r) + tf.square(sita))+get_loss()  
            g = tf.gradients(loss,self.testmodel.trainable_variables)
            self.opt.apply_gradients(grads_and_vars = zip(g,self.testmodel.trainable_variables))         
        def get_loss():
            temp_l = []
            for each in points:
                temp_l.append(self.get_kennel_point(each,self.testmodel.trainable_variables))
            return tf.exp(-sum(temp_l)) 

        for i in range(200): 
            r,sita = self.testmodel(self.r,self.sita)
            g = tf.gradients(loss,self.testmodel.trainable_variables)
            base = aita*tf.exp(-tf.reduce_sum(tf.square(g))/loss)
            aim = tf.random.normal([],aita*e,d,dtype = tf.float32)
            q = base - aim
            cond = q*10 < self.af
            tf.cond(cond,add_point_opt,commen_opt)
            tf.print(i)
        return self.testmodel.trainable_variables,loss
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章