(三)tensorflow2.0 - 自定義loss function(損失函數)


前文分別講了tensorflow2.0中自定義Layer和自定義Model,本文將來討論如何自定義損失函數。

(一)tensorflow2.0 - 自定義layer
(二)tensorflow2.0 - 自定義Model
(三)tensorflow2.0 - 自定義loss function(損失函數)
(四)tensorflow2.0 - 實戰稀疏自動編碼器SAE


自定義損失函數有兩種情況,一種比較簡單,而另一種稍顯復雜。
先來討論第一種簡單的情況,即不需要額外的參數。
什么叫額外的參數呢?損失函數有兩個默認參數,分別為實際輸出、預測輸出,如果損失函數只需要這兩個參數,那么設計起來就很方便。

# 定義損失函數
def custom_loss(y_actual,y_pred):
    custom_loss= (y_actual-y_pred)**2
    return custom_loss

# 使用該loss function
model.compile(loss=custom_loss, optimizer=...)

這種情況下,y_actualy_pred的值會自動傳入該損失函數中,無需操心,這種實現也比較簡單。

第二種情況,損失函數需要額外的參數,即損失函數需要的數據不止是預測值和真實值這么簡單,比如我要添加一個權重的懲罰項以防權重過大,這時上面方法就行不通了。

這種情況沒辦法,只能自己自行設計模型運行流程了。

class SAEModel(Model):
    # 可以傳入一些超參數,用以動態構建模型
    # __init__()方法在創建模型對象時被調用
    def __init__(self, input_shape, hidden_shape=None):
        # 隱藏層節點個數默認為輸入層的3倍
        if hidden_shape == None:
            hidden_shape = 3 * input_shape
        # 調用父類__init__()方法
        super(SAEModel, self).__init__()
        
        self.layer_1 = SAELayer(hidden_shape)
        self.layer_2 = layers.Dense(input_shape, activation=tf.nn.sigmoid)

    def call(self, input_tensor, training=False):
        # 輸入數據
        hidden = self.layer_1(input_tensor)
        output = self.layer_2(hidden)
        return output
    
    # 計算損失值
    def get_loss(self, input_tensor):
        hidden = self.layer_1(input_tensor)
        output = self.layer_2(hidden)
        
        # 計算loss
        # 計算MSE
        mse = (1 / 2) * tf.reduce_sum(kb.square(input_tensor - output))
        # 計算權重乘法項
        alpha = 0.1
        W1 = self.layer_1.kernel
        W2 = self.layer_2.kernel
        weightPunish = (alpha / 2) * (tf.reduce_sum(kb.square(W1)) + tf.reduce_sum(kb.square(W2)))
        ans = tf.constant(mse + weightPunish)
        return ans
    
    def get_grad(self, input_tensor):
        with tf.GradientTape() as tape:
            tape.watch(self.variables)
            L = self.get_loss(input_tensor)
            g = tape.gradient(L, self.variables)
        return g

    def network_learn(self, input_tensor):
        g = self.get_grad(input_tensor)
        optimizers.Adam().apply_gradients(zip(g, self.variables))
        

在本模型中,為了自定義帶有額外參數的loss function(即權重懲罰項),因此需要對整個模型的流程進行自定義。傳統模型只需包括__init__()方法和call()方法即可,但在本例中,可以看出call()方法中的代碼被get_loss()方法囊括了,這樣是為了方便在計算損失函數時獲得需要的參數。
本模型執行流程為:network_learn -> get_grad -> get_loss(執行一次神經網絡訓練過程,並計算損失值) -> get_grad(根據返回的損失值計算梯度並返回) -> network_learn(根據返回的梯度,使用某種優化器(本例為Adam)更新模型中所有需要訓練的參數(也可以指定某些參數))

訓練過程也變了,代碼如下,需要手動進行設置了:

saeModel = SAEModel(inputList.shape[-1], hiddenNum)
for i in range(1000):
	saeModel.network_learn(tf.constant(inputList))

到此,我已介紹完如何使用tensorflow2.0自定義Layer、自定義Model、自定義Loss Function,接下來將會將這三者結合起來,實現一個完整的例子——(四)tensorflow2.0 - 實戰稀疏自動編碼器SAE


參考文獻:


免責聲明!

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



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