天天看點

用 Keras/TensorFlow 2.8 建立 COCO 的 average precision 名額前言1. AP 的算法原理。2. 在 Keras 中的實作。3. 建立狀态量。4. update_state 方法。5. result 方法。6. 測試盒 testcase。7. 使用方法。8. 下載下傳連結。THE END

文章目錄

  • 前言
  • 1. AP 的算法原理。
  • 2. 在 Keras 中的實作。
  • 3. 建立狀态量。
  • 4. update_state 方法。
    • 4.1 更新第一個狀态量 showed_up_classes 。
    • 4.2 更新另外兩個狀态量。
  • 5. result 方法。
  • 6. 測試盒 testcase。
  • 7. 使用方法。
  • 8. 下載下傳連結。
  • THE END

前言

YOLO 系列(包括 YOLOv4-CSP,YOLOv4 等)的探測器 detector,它們的損失函數由 3* 部分組成。如果這 3 部分的每一個部分都使用一個名額,将得到 3 個獨立的名額。這會使得訓練模型變得更困難(比如一個名額變好,另一個名額卻變壞的情況)。

正如吳恩達教授在《機器學習政策》(Introduction to Machine Learning Strategy)課程中所提到的,當一個模型有多個名額時,應該盡量把它們合并成一個最重要的優化名額,才能使得模型有明确的優化方向。而 COCO 資料集的 average precision 名額,就是最合适的優化名額。

  • *這 3 部分損失是:1. 判斷預設框 anchor box 内是否有物體的預測損失。2. 判斷預設框内的物體,屬于哪一個類别的預測損失。3. 預測結果物體框和标簽物體框,兩者之間的 CIOU 損失。

1. AP 的算法原理。

COCO 資料集的 AP(average precision) 名額,實際上是對 average precision 計算了兩次平均值,主要算法有如下 3 個步驟:

  1. 設定 IoU 門檻值為 0.5,計算一個類别的 AP。
  2. 重複上面的第一步,計算 80 個類别 AP,然後對 80 個類别 AP 求平均值,得到一個 average_precision_over_categories。
  3. 周遊 10 個 IoU 門檻值(0.5,0.55, 0.6,…, 0.95,以 0.05 為步進值),重複上面的 2 個步驟,得到 10 個 average_precision_over_categories,然後對這 10 個 average_precision_over_categories 求平均值,就得到一個 mean average precision。這個 mean average precision 就是 COCO 的 AP。

COCO 資料集聲明不區分 AP 和 mAP(mean average precision),統一使用 AP 這個詞,由使用者根據使用場景自行區分是 AP 還是 mAP。如果想要區分的話,簡單來說,對單個類别就是 AP,求了兩次平均值之後就是 mAP(mean average precision)。

2. 在 Keras 中的實作。

下面我們用 Keras/TensorFlow 2.8 來建立 COCO 的 AP 名額,并詳細解釋其算法原理。

Keras 中有一個專門用于名額的類: tf.keras.metrics.Metric。可以用它來建立一個類 MeanAveragePrecision,來計算 AP 名額。

名額類 tf.keras.metrics.Metric 中,有 3 個主要的方法,update_state、 result 和 reset_state。這 3 個方法的具體作用是:

  1. 方法 update_state,根據每個 batch 的計算結果,對狀态量進行更新。
  2. 方法 result,使用更新好的狀态量,計算名額。
  3. 方法 reset_state,用于在每個 epoch 開始時,把狀态量重新設定為初始狀态。

在代碼中的名額 MeanAveragePrecision 和 3 個方法如下圖。

用 Keras/TensorFlow 2.8 建立 COCO 的 average precision 名額前言1. AP 的算法原理。2. 在 Keras 中的實作。3. 建立狀态量。4. update_state 方法。5. result 方法。6. 測試盒 testcase。7. 使用方法。8. 下載下傳連結。THE END

對于 COCO 的 AP 來說,主要用到類别置信度和 IoU 這兩個資料,是以方法 update_state 将主要更新這 2 個資料,而方法 result 也将主要使用這 2 個資料來計算 AP。

下面的程式僞代碼中,會經常提到 4 個詞語,這裡先明确一下這 4 個詞語的定義:

  1. objectness:是一個機率值,表示對于目前物體框,框内有物體存在的機率。(YOLO 論文中使用該詞,中文的翻譯應該是 “物體框内有物體存在的置信度”。為了便于和下面第二條的類别置信度進行差別,這裡沿用論文的寫法,用 objectness。)
  2. 類别置信度:也是一個機率值,表示對于目前物體框内物體,屬于某個類别的機率大小。
  3. “正樣本”:正樣本的意思,是指一個 bbox(它的 objectness 和類别置信度都大于對應的門檻值)。
  4. 相關圖檔:是指該圖檔的标簽或是預測結果的正樣本中,包含了該類别。

3. 建立狀态量。

用名額類 tf.keras.metrics.Metric 建立的是完整狀态的名額 stateful metric,意思是可以用它來計算很複雜的名額。通常需要先建立相關的狀态量 states。

對于 COCO 的 AP 名額,需要建立 3 個狀态量 latest_positive_bboxes、 labels_quantity_per_image 和 showed_up_classes,3 個狀态量類型均為 tf.Variable。

  1. latest_positive_bboxes,形狀為 (CLASSES, latest_related_images, bboxes_per_image, 2)。記錄的是對于每一個類别,使用 latest_related_images 張相關圖檔,計算得到的狀态值。

    而對于每一張相關圖檔,其對應的狀态張量形狀為 (bboxes_per_image, 2),記錄了 bboxes_per_image 個 bboxes 的狀态。

    每個 bboxes 的狀态是一個長度為 2 的向量,兩個值分别是類别置信度和 IoU 值。

  2. labels_quantity_per_image,形狀為 (CLASSES, latest_related_images)。記錄的是對于每一個類别,在 latest_related_images 張相關圖檔中,标簽 bboxes 的數量。

    這個狀态張量和 latest_positive_bboxes 是一一對應的。也就是說,如果狀态 latest_positive_bboxes 中記錄了一個相關圖檔的置信度和 IoU,則 labels_quantity_per_image 也必須記錄該圖檔中的标簽 bboxes 數量。

  3. showed_up_classes,形狀為 (CLASSES, ),是一個布爾張量,記錄的是所有圖檔中出現過的類别。

    在計算 AP 時,隻有出現過的類别,才能參與計算 AP,是以需要用 showed_up_classes 進行記錄。

建立好的 3 個狀态量如下圖。

用 Keras/TensorFlow 2.8 建立 COCO 的 average precision 名額前言1. AP 的算法原理。2. 在 Keras 中的實作。3. 建立狀态量。4. update_state 方法。5. result 方法。6. 測試盒 testcase。7. 使用方法。8. 下載下傳連結。THE END

在上圖中有 3 點要注意:

  1. 為了實作 P3, P4, P5 共用狀态量 states,把狀态量建立在類 MeanAveragePrecision 的外部。這是因為 YOLOv4-CSP 和 YOLOv4 等模型,有 P3, P4, P5 一共 3 個輸出。如果狀态量建立在 MeanAveragePrecision 的内部,這些狀态量實際上将會是複制了 3 份,即 3x3=9 個獨立的狀态量。
  2. 設定 trainable=False。因為這 3 個狀态量是 tf.Variable,預設會求梯度并進行反向傳播。但是對名額的狀态量來說,并不需要進行反向傳播,是以設定 trainable=False,可以節省計算資源。
  3. 狀态量的形狀,受 2 個全局變量 latest_related_images, bboxes_per_image 控制。如果電腦的算力足夠,可以把這兩個變量設定得大一些。

4. update_state 方法。

在每個 batch 計算完成之後,要用方法 update_state 對 3 個狀态量進行更新。

4.1 更新第一個狀态量 showed_up_classes 。

下面是程式的僞代碼,用到一些變量的名字,和程式中的變量名字相同,以友善閱讀代碼。

  1. 從标簽中提取出現過的類别,得到張量 showed_up_categories_label,張量形狀為 (x,),裡面存放的是出現過的類别編号,表示有 x 個類别出現在了這批标簽中。

    1.1 showed_up_categories_index_label = tf.experimental.numpy.isclose(objectness_label, 1)

    1.2 showed_up_categories_label = tf.argmax(y_true[…, 1: 81], axis=-1),showed_up_categories_label 形狀為 (batch_size, *Feature_Map_px, 3)。在代碼中會以 *Feature_Map_px 表示 P5, P4, P3 的特征圖大小,一般 P5 特征圖大小為(19, 19)。

    1.3 showed_up_categories_label = showed_up_categories_label[showed_up_categories_index_label],showed_up_categories_label 形狀為 (x, )。

    注意不能僅使用 argmax,而是必須借助上面的第 1.3 步驟,使用 showed_up_categories_index_label 作為索引。因為在沒有标簽時,argmax 也會得出一個值 0,而這個 0 并不表示該物體框的類别為 0 。

  2. 從預測結果中提取出現過的類别,得到張量 showed_up_categories_pred,張量形狀為 (y,),裡面存放的是出現過的類别編号,表示有 y 個類别出現在了這批預測結果中。
  3. 将上面 2 個張量改變形狀為 (1, -1),然後用 tf.sets.union 求并集,得到一個 sparse tensor, 将其轉換為 tf.tensor,得到張量 showed_up_categories_batch,張量形狀為 (categories_batch,)。
  4. 周遊 showed_up_categories_batch,對每一個出現過的類别 category,如果之前還沒有出現過,則設定 showed_up_classes[category].assign(True)。

4.2 更新另外兩個狀态量。

3 大主要操作步驟如下:

  1. 第一重循環,周遊批次結果資料中的每一張圖檔(方法 update_state 中接收的是單個批次的結果,是以要周遊批次中的每張圖檔),對每一張圖檔執行下面 2 步操作。
  2. 對于單張圖檔的标簽 one_label 和預測結果 one_pred,分别構造相應的張量。

    2.1 對于标簽:構造張量 positives_index_label,positives_label 和 category_label。

    positives_index_label 形狀為 (19, 19, 3),是一個布爾張量,是标簽正樣本的索引張量,即隻有 objectness 等于 1 的 bboxes,其對應布爾值才會為 True。

    為了友善描述,這裡的形狀隻以 YOLOv4-CSP 模型的 P5 形狀為例。下面也是如此。

    建立标簽的正樣本張量:

    positives_label = tf.where(condition=positives_index_label[…, tf.newaxis], x=one_label, y=-8.0],positives_label 形狀為 (19, 19, 3,85), 裡面隻有正樣本資訊,其它位置的數值為 -8。(使用 -8 而沒有使用 -1,是為了便于和 axis=-1 混淆,友善搜尋)

    建立标簽的類别張量:

    category_label = tf.math.argmax(positives_label[…, 1: 81], axis=-1),category_label 形狀為 (19, 19, 3),代表每一個正樣本的類别。在不是正樣本的位置,數值為 0。因為這個 0 會和類别編号 0 發生混淆,是以下面要用 tf.where 再次進行轉換,使得在不是正樣本的位置,其數值為 -8。

    category_label = tf.where(condition=positives_index_label, x=category_label, y=-8)

    2.2 對于預測結果:構造張量 positives_index_pred,positives_pred 和 category_pred。

    positives_index_pred 形狀為 (19, 19, 3),是一個布爾張量,是預測結果正樣本的索引張量,即隻有 objectness 和類别置信度都大于門檻值的 bboxes,其對應布爾值才會為 True。

    構造另外 2 個張量的方法,和構造對應的标簽張量方法相同。這裡不再贅述。

  3. 第二重循環,周遊 80 個類别,區分 4 種情況,更新狀态值。

先建立标簽類别的布爾值 category_bool_any_label,和預測結果的布爾值 category_bool_any_pred,兩者均為标量型張量,如果有任何一個物體框内物體屬于目前類别,則對應布爾值為 True:

category_bool_label = tf.experimental.numpy.is_close(category_label, category)
category_bool_any_label = tf.reduce_any(category_bool_label)

category_bool_pred = tf.experimental.numpy.is_close(category_pred, category)
category_bool_any_pred = tf.reduce_any(category_bool_pred)
           

對每一個類别,都要區分 4 種情況,計算得到兩個張量 one_image_positive_bboxes 和 one_image_category_labels_quantity,分别用來更新兩個狀态量 latest_positive_bboxes 和 labels_quantity_per_image。

對 4 種情況建構布爾張量:

情況 a :标簽和預測結果中,都沒有該類别。無須更新狀态。

情況 b :預測結果中沒有該類别,但是标簽中有該類别。布爾張量為 scenario_b = tf.logical_and(~category_bool_any_pred, category_bool_any_label)。

此時需要提取預測結果的類别置信度和 IoU,且類别置信度和 IoU 都為 0。另外還需要提取标簽數量。

情況 c :預測結果中有該類别,标簽沒有該類别。布爾張量為 scenario_c = tf.logical_and(category_bool_any_pred, ~category_bool_any_label)。

此時需要提取預測結果的類别置信度和 IoU。而因為沒有标簽,IoU 為0。另外還需要提取标簽數量 0。

情況 d :預測結果和标簽中都有該類别,布爾張量為 scenario_d = tf.logical_and(category_bool_any_pred, category_bool_any_label)。

此時需要提取預測結果的類别置信度和 IoU。IoU 要經過計算得到。另外還需要提取标簽數量。

隻有在情況 b,c,d 時,才需要更新 2 個狀态量,是以先要判斷是否處在情況 b,c,d 下,再決定是否執行後續步驟。

under_scenarios_bc = tf.logical_or(scenario_b, scenario_c)
under_scenarios_bcd = tf.logical_or(under_scenarios_bc, scenario_d)

if under_scenarios_bcd:
    提取 b,c,d 三種情況的置信度和 IoU,更新另外 2 個狀态量。
           

對于每一個類别來說,a,b,c,d 情況不會同時發生,隻可能出現其中的一種,因為這 4 種情況是互斥的。

下面是 b,c,d 情況下,詳細的操作步驟。

情況 b:

one_image_positive_bboxes = tf.zeros(shape=(BBOXES_PER_IMAGE, 2)),可以直接把 one_image_positive_bboxes 作為輸出張量。

情況 c,需要提取類别置信度和 IoU,有 5 個操作步驟:

  1. 先擷取目前情況的正樣本:

    scenario_c_positives_pred = positives_pred[category_bool_pred],scenario_c_positives_pred 形狀為 (scenario_c_bboxes, 85)。

  2. 再擷取目前情況的類别置信度:

    scenario_c_classification_confidence_pred = tf.reduce_max(scenario_c_positives_pred[:, 1: 81]),scenario_c_positives_pred 形狀為 (scenario_c_bboxes,)。

  3. 比較 scenario_c_bboxes 和 bboxes_per_image 的大小,區分兩種情況:

    3.1 如果 scenario_c_bboxes < bboxes_per_image:

    使用 tf.pad,對 scenario_c_classification_confidence_pred 尾部進行補零,得到新的張量 one_image_positive_bboxes,其形狀變為 (bboxes_per_image,) 。

    3.2 如果 scenario_c_bboxes ≥ bboxes_per_image:

    按照置信度從大到小的順序,對 scenario_c_classification_confidence_pred 進行排序,得到 scenario_c_sorted_pred,其形狀為 (scenario_c_bboxes,)。

    之是以要進行排序,是因為在最後計算 AP 時,需要按置信度從大到小進行排序後,才會計算 AP。是以目前步驟在篩選 bboxes 時,也就應該把置信度大的 bboxes 篩選出來。

    保留置信度較大的 bboxes,即 one_image_positive_bboxes = scenario_c_sorted_pred[:bboxes_per_image],one_image_positive_bboxes 形狀為 (bboxes_per_image,) 。

  4. 擷取 IoU(情況 c 的 IoU 為 0,情況 d 的 IoU 需要經過計算得到)。

    因為标簽中沒有這個類别,是以 IoU 為 0,可以使用 scenario_c_ious_pred = tf.zeros_like(one_image_positive_bboxes).

  5. 将置信度和 IoU 進行堆疊 stack。

    one_image_positive_bboxes = tf.stack(values=[one_image_positive_bboxes, scenario_c_ious_pred], axis=1),one_image_positive_bboxes 形狀為 (bboxes_per_image, 2)。

情況 d:此時需要計算 IoU,6 個步驟如下(因為隻有和标簽 IoU 最大的預測結果 bbox,才認為是命中了該标簽,是以需要對每一個标簽,同時和所有的預測結果 bboxes 計算 IoU):

  1. 對于預測結果:取出屬于目前類别的 bboxes,把每個 bbox 資訊填入全零數組 bboxes_iou_pred,其它多餘的位置保持數值為 0。bboxes_iou_pred = tf.where(condition=category_bool_pred, x=positives_pred[…, -4:], y=0],bboxes_iou_pred 形狀為 (19, 19, 3,4)。
  2. 對于标簽:取出屬于目前類别的 bboxes,即 bboxes_category_label = positives_label[…, -4:][category_bool_label],bboxes_category_label 形狀為 (scenario_d_bboxes_label,4)。
  3. 對 bboxes_category_label,按照面積從小到大的順序進行排序(展現着重小物體的思想,善于識别小物體的模型,其名額将越好),得到 sorted_bboxes_label,形狀為 (scenario_d_bboxes_label, 4)。
  4. 建立張量 one_image_positive_bboxes = tf.zeros(shape=(BBOXES_PER_IMAGE, 2))。設定計數變量 new_bboxes_quantity = 0.
  5. 周遊 sorted_bboxes_label,對每一個标簽 bbox,執行如下 3 個操作:

    5.1 把其資訊填入全 1 張量 bbox_iou_label(即張量最後一個次元,所有長度為 4 的向量,寫的都是同一個 bbox 的資訊),bboxes_iou_pred 形狀為 (19, 19, 3, 4)。

    5.2 用 bbox_iou_label 和 bboxes_iou_pred 計算 ious_category,ious_category 張量形狀為 (19, 19, 3)。

    5.3 如果最大 IoU 大于門檻值 0.5,則認為預測結果中對應的 bbox 命中了标簽,做 2 個操作:

    5.3.1 将該 bbox 的類别置信度和 IoU 記錄到張量 one_image_positive_bboxes 中(用 tf.concat)。

    5.3.2 從 bboxes_iou_pred 去掉該 bbox(用 tf.where),後續計算 IoU 不需要再考慮這個 bbox。

    5.3.3 new_bboxes_quantity += 1.

    5.4 new_bboxes_quantity 等于 bboxes_per_image 時,停止記錄新的 bboxes。

  6. 周遊 sorted_bboxes_label 完成之後,如果 bboxes_iou_pred 有剩餘的 bboxes,說明這些 bboxes 沒有命中任何标簽。如果還滿足條件 new_bboxes_quantity < BBOXES_PER_IMAGE,則需要将剩下 bboxes 的 IoU 設為 0,并記錄到張量 one_image_positive_bboxes 中。

    令剩餘 bboxes 數量為 left_bboxes_quantity, 加到 one_image_positive_bboxes 後,總的 bboxes 數量為 scenario_d_bboxes = new_bboxes_quantity + left_bboxes_quantity。

    求出剩餘的 bboxes,得到 left_bboxes_pred, 形狀為 (left_bboxes_quantity, 85)。

    left_bboxes_confidence_pred = tf.reduce_max(left_bboxes_pred[:, 1: 81])

    6.1 如果 scenario_d_bboxes > bboxes_per_image,則需要進行排序:

    6.1.1 按照置信度從大到小的順序,對 left_bboxes_confidence_pred 進行排序,得到 left_bboxes_sorted_confidence,其形狀為 (left_bboxes_quantity,)。

    之是以要進行排序,是因為在最後計算 AP 時,需要按置信度從大到小進行排序後,才會計算 AP。

    6.1.2 vacant_seats = BBOXES_PER_IMAGE - new_bboxes_quantity

    6.1.3 left_bboxes_confidence_pred = left_bboxes_sorted_confidence[:vacant_seats]。

    6.2 如果 scenario_d_bboxes ≤ bboxes_per_image,則無須進行排序,可以直接使用left_bboxes_confidence_pred。

    6.3 給 left_bboxes_confidence_pred 加上全為 0 的 IoU (使用 tf.stack),得到 left_positive_bboxes_pred,形狀為(vacant_seats, 2)。

    6.4 将 left_positive_bboxes_pred 和 one_image_positive_bboxes 進行拼接 concatenate,然後保留最後 bboxes_per_image 個 bboxes,即 one_image_positive_bboxes = one_image_positive_bboxes[-bboxes_per_image:]。

計算标簽數量,得到整數 one_image_category_labels_quantity = tf.where(category_bool_label).shape[0]。

最後更新 2 個狀态量,更新原則為先進先出 FIFO。

1. 用張量 one_image_positive_bboxes 更新狀态量 latest_positive_bboxes。
latest_positive_bboxes 形狀為 (CLASSES, latest_related_images, bboxes_per_image, 2)。

latest_positive_bboxes[category, 1:].assign(latest_positive_bboxes[category, :-1])
latest_positive_bboxes[category, 0].assign(one_image_positive_bboxes)


2. 用整數 one_image_category_labels_quantity 更新狀态量 labels_quantity_per_image。
labels_quantity_per_image 形狀為 (CLASSES, latest_related_images)。

labels_quantity_per_image[category, 1:].assign(labels_quantity_per_image[category, :-1])
labels_quantity_per_image[category, 0].assign(one_image_category_labels_quantity)
           

5. result 方法。

方法 result 的作用,是使用狀态量來計算名額。

需要注意的是,YOLO-v4-CSP 是多輸出模型,有 P3, P4, P5 這 3 個輸出,是以在每批次資料計算完成之後,會在這 3 個輸出上分别計算一次名額。可以設定跳過 P4, P5,隻計算 P3 的名額。

在方法 result 中,根據自頂向下的程式結構,頂層的程式隻有 2 個大步驟:

  1. 周遊 10 個 IoU 門檻值,對每一個 IoU 門檻值,計算 1 個 average_precision_over_categories:

    1.1 周遊 80 個類别,對每一個類别,計算 1 個 AP。

    1.2 對 80 個 AP 取平均值,得到 average_precision_over_categories。

  2. 将最終的 10 個 average_precision_over_categories 取平均值,就得到最終的 mAP。

在上面的步驟 1.1 中,計算單個類别的 average_precision 時,如果 labels_quantity = 0,直接設 AP = 0。

而如果 labels_quantity 不等于 0,則需要計算 AP,有如下 2 個操作:

  1. 計算 recall_precisions。

    1.1 建立空的張量 recall_precisions,形狀為 (1,)。其索引為 recall,設定初始 recall = 0, recall_precisions[0] = 1。後續每一個 recall 值都對應一個 precision 值。

    1.2 設定 true_positives = 0,false_positives = 0。

    1.3 從 latest_positive_bboxes 中,取出目前類别的所有 bboxes,形狀是 (bboxes_per_image * latest_related_images, 2)。每個 bbox 包含 2 個資訊:類别置信度和 IoU。

    1.4 按照類别置信度,進行由大到小的排序,得到張量 sorted_bboxes_category。

    1.5 周遊 sorted_bboxes_category 中的所有 bboxes,計算得到 recall_precisions (使用類别置信度進行過濾。如果置信度為 0,說明它不是模型的預測結果,不應該參與計算 AP)。

    1.5.1 如果該 bbox 的 IoU 大于目前的 IoU 門檻值,則認為該預測正樣本命中,更新 2 個數值, true_positives += 1, recall += 1。

    1.5.2 如果 IoU 小于門檻值,則更新 1 個數值 false_positives += 1。

    1.5.3 計算 precision = true_positives/(false_positives + true_positives),然後更新張量 recall_precisions,即 recall_precisions[recall] = precision 。

  2. 計算 AP。

    周遊 sorted_bboxes_category 完成後,使用張量 recall_precisions,計算多個小梯形面積,累加所有小梯形的面積,得到 AP。

    2.1 從 labels_quantity_per_image 中,獲得 latest_images 個相關圖檔的标簽 bboxes 總數 labels_quantity,而 1/labels_quantity 則是小梯形的高度 trapezoid_height。

    2.2 從 recall_precisions 的第 0 個索引位置開始,計算小梯形面積 (recall_precisions[0] + recall_precisions[1]) * trapezoid_height / 2。直到 recall_precisions 的倒數第 2 個索引位置結束。

    2.3 把所有的小梯形面積累加起來,就得到該類别的 AP。

6. 測試盒 testcase。

做了一個測試盒 testcase,盒子裡放了 13 個單元測試。目前 AP 名額通過了盒子裡全部的 13 個測試。

如果使用者需要改動這個名額,也應該用測試盒再測試一下,確定名額能正常運作。

對于企業使用者,當然應該按照軟體工程的要求,由軟體測試團隊進行專業的測試之後,才能使用。

測試盒程式的部分截圖如下:

用 Keras/TensorFlow 2.8 建立 COCO 的 average precision 名額前言1. AP 的算法原理。2. 在 Keras 中的實作。3. 建立狀态量。4. update_state 方法。5. result 方法。6. 測試盒 testcase。7. 使用方法。8. 下載下傳連結。THE END

7. 使用方法。

在使用這個 AP 名額檔案時,注意以下 3 點:

  1. 該名額需要配合使用 YOLO 系列的模型,比如 YOLOv4-CSP, YOLOv4 等等。

    因為 YOLO 系列的模型有 p3, p4, p5 共 3 個輸出,名額也是針對這 3 個輸出寫的。如果需要用到其它的探測器 detector上,需要自行修改名額檔案。

  2. 該名額檔案可以運作在 TensorFlow 2.8 環境下。如果要使用更低版本的 TensorFlow,可能需要自行修改檔案中的少量代碼。

    舉例來說,如下左圖,在 TF 2.4 中,isclose 函數的結果是一種特殊的 TF 數組。該數組無法直接用做張量的索引,需要先手動将其轉換成張量。這可以算作 TF 2.4 的一個 bug。

    而到了 TF 2.8,修複了這個問題,isclose 函數的結果是一個 TF 張量,可以直接用做張量的索引,友善了很多。如下右圖。

    用 Keras/TensorFlow 2.8 建立 COCO 的 average precision 名額前言1. AP 的算法原理。2. 在 Keras 中的實作。3. 建立狀态量。4. update_state 方法。5. result 方法。6. 測試盒 testcase。7. 使用方法。8. 下載下傳連結。THE END
  3. 該名額可能需要在 eager 模式下運作。

    在圖模式下,該名額會生成計算圖,将占用大量的記憶體,超過 128G,是以個人的桌上型電腦難以将其運作在圖模式下,需要使用 eager 模式。

    對于企業使用者,有大量的記憶體和算力的條件下,可以嘗試用圖模式。

    要在 eager 模式下運作該名額,直接在編譯模型時設定 run_eagerly=True 即可,示例如下:

yolo_v4_csp_model.compile(
	run_eagerly=True, 
	metrics=average_precision,
	loss=my_custom_loss, 
	optimizer=optimizer_adam)
           

8. 下載下傳連結。

代碼已在 Github 開源,可以直接下載下傳。→ 下載下傳連結在此

一共有 2 個相關檔案,名額檔案 average_precision_metric.py 和測試盒檔案 testcase_average_precision.py。

THE END

繼續閱讀