paddle 嘗試實現 focal loss

paddle 裏面沒有 focal loss 的API,不過這個loss函數比較簡單,所以決定自己實現嘗試一下。在 paddle 裏面實現類似這樣的功能有兩種選擇:

  • 使用 paddle 現有的 op 去組合出來所需要的能力
  • 自己實現 op
    • python 端實現 op
    • C++ 端實現 op

兩種思路都可以實現,但是難度相差很多,前者比較簡單,熟悉 paddle 的數學操作,理解公式含義即可。後者又分兩種方式,python 端實現相對簡單,C++端實現比較複雜。這次嘗試用 paddle 的 op 組合實現。

理解 focal loss

最早出現在單階段目標檢測當中。單階段訓練時正負樣本比例難以控制,loss 被大量的負樣本充斥,導致反向傳播時向着調整負樣本方向前進,而正樣本的訓練不佳。爲了解決這個問題,何凱明大神提出了 focal loss 損失函數調節正負樣本權重,同時還能進一步調節難易樣本的權重。進一步的理解可上網查看,資料很多。原版 focal loss 的公式如下:

loss = -at·(1 - pt)^r · log(pt)

at和r 是超參數,分別用於控制正負樣本的權重和難易樣本的權重。對於多分類而言。at 不太好處理,因此這次實現暫時忽略,後續想法是根據各個類別佔總樣本中的比例設置

# 調試打印函數,通過 py_func 實現打印參數值的 op,方便調試
def print_func(var):
    logger.info("in py func type: {0}".format(type(var)))
    print(np.array(var))
 
 
# 不帶類別平衡的 focal loss,僅僅區分類別難易;猜測此時算出來的梯度有一個 gama 倍,所以學習率可以比以往更小一點
def focal_loss(pred, label, gama):
    # 使用打印函數查看當前 Tensor,
    # fluid.layers.py_func(func=print_func, x=pred, out=None)
    one_hot = paddle.fluid.layers.one_hot(label, train_parameters['class_dim'])
    prob = one_hot * pred
    cross_entropy = one_hot * fluid.layers.log(pred)
    cross_entropy = fluid.layers.reduce_sum(cross_entropy, dim=-1)
    sum = paddle.fluid.layers.sum(cross_entropy)
    weight = -1.0 * one_hot * paddle.fluid.layers.pow((1.0 - pred), gama)
    weight = fluid.layers.reduce_sum(weight, dim=-1)
    return weight * cross_entropy
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章