Datawhale AI 夏令營 第五期 CV方向 02進階

程序员shaun發表於2024-08-29

上次的baseline方案,訓練的模型,獲得分數並不高,DataWhale提供了兩個上分的思路

  1. 增加訓練資料集
  2. 切換不同模型預訓練權重

增加訓練集的大小通常可以提高模型的泛化能力,因為更多的資料可以幫助模型學習到更多的特徵和模式。但是,越大的資料集,就意味著需要更多的計算資源和時間來訓練模型,以及可能出現的過擬合問題。

增加訓練資料集

增大資料集的一些方法:

  1. 資料增強: 透過對現有資料進行變換(如旋轉、縮放、裁剪、顏色調整等)來增加資料集的多樣性。

  2. 合成資料: 使用資料合成技術生成新的訓練樣本,尤其是在資料稀缺的情況下。

  3. 資料探勘: 從網際網路或公共資料集中收集更多相關資料。

  4. 眾包: 利用眾包平臺收集和標註資料。

  5. 遷移學習: 使用預訓練模型作為起點,然後在較小的資料集上進行微調。

  6. 分層抽樣: 確保資料集中的每個類別都有足夠數量的樣本。

  7. 交叉驗證: 使用交叉驗證來更有效地利用有限的資料,同時評估模型的穩定性。

  8. 正則化技術: 如L1或L2正則化,以減少過擬合的風險。

  9. 早停法: 在驗證集上的效能不再提升時停止訓練,以避免過擬合。

  10. 調整模型複雜度: 根據資料集的大小調整模型的複雜度,以找到最佳的模型容量。

這裡,我們直接從資料集中劃分更多的資料作為訓練資料,同時,驗證集也增大

訓練集增大到30

for anno_path, video_path in zip(train_annos[:30], train_videos[:30]):
    print(video_path)
    anno_df = pd.read_json(anno_path)
    cap = cv2.VideoCapture(video_path)
    frame_idx = 0 
    while True:
        ret, frame = cap.read()
        if not ret:
            break

        img_height, img_width = frame.shape[:2]
        
        frame_anno = anno_df[anno_df['frame_id'] == frame_idx]
        cv2.imwrite('./yolo-dataset/train/' + anno_path.split('/')[-1][:-5] + '_' + str(frame_idx) + '.jpg', frame)

        if len(frame_anno) != 0:
            with open('./yolo-dataset/train/' + anno_path.split('/')[-1][:-5] + '_' + str(frame_idx) + '.txt', 'w') as up:
                for category, bbox in zip(frame_anno['category'].values, frame_anno['bbox'].values):
                    category_idx = category_labels.index(category)
                    
                    x_min, y_min, x_max, y_max = bbox
                    x_center = (x_min + x_max) / 2 / img_width
                    y_center = (y_min + y_max) / 2 / img_height
                    width = (x_max - x_min) / img_width
                    height = (y_max - y_min) / img_height

                    if x_center > 1:
                        print(bbox)
                    up.write(f'{category_idx} {x_center} {y_center} {width} {height}\n')
        
        frame_idx += 1

驗證集

for anno_path, video_path in zip(train_annos[-10:], train_videos[-10:]):
    print(video_path)
    anno_df = pd.read_json(anno_path)
    cap = cv2.VideoCapture(video_path)
    frame_idx = 0 
    while True:
        ret, frame = cap.read()
        if not ret:
            break

        img_height, img_width = frame.shape[:2]
        
        frame_anno = anno_df[anno_df['frame_id'] == frame_idx]
        cv2.imwrite('./yolo-dataset/val/' + anno_path.split('/')[-1][:-5] + '_' + str(frame_idx) + '.jpg', frame)

        if len(frame_anno) != 0:
            with open('./yolo-dataset/val/' + anno_path.split('/')[-1][:-5] + '_' + str(frame_idx) + '.txt', 'w') as up:
                for category, bbox in zip(frame_anno['category'].values, frame_anno['bbox'].values):
                    category_idx = category_labels.index(category)
                    
                    x_min, y_min, x_max, y_max = bbox
                    x_center = (x_min + x_max) / 2 / img_width
                    y_center = (y_min + y_max) / 2 / img_height
                    width = (x_max - x_min) / img_width
                    height = (y_max - y_min) / img_height

                    up.write(f'{category_idx} {x_center} {y_center} {width} {height}\n')
        
        frame_idx += 1

切換不同模型預訓練權重

先了解一下YOLO系列中常見的不同版本(s, m, l, x)的區別:

  1. YOLO-S (Small): 這是YOLO系列中的小型版本,通常具有較少的引數和較低的計算需求。它適用於資源受限的環境,如移動裝置或嵌入式系統,但可能在檢測精度上有所犧牲。

  2. YOLO-M (Medium): 中型版本提供了一個平衡點,它比小型版本有更多的引數和更高的計算需求,同時保持了較好的檢測精度和速度。

  3. YOLO-L (Large): 大型版本擁有最多的引數和最高的計算需求。它提供了更高的檢測精度,但速度可能會慢於小型和中型版本。

  4. YOLO-X (Extra Large): 這是YOLO系列中的超大型版本,它具有最多的引數和最高的計算需求。YOLO-X通常用於需要最高精度的場景,儘管它的速度可能不如其他版本快。

這裡選擇了YOLOv8s的預訓練模型

同時增加訓練回合

import os
os.environ["CUDA_VISIBLE_DEVICES"] = "0"

import warnings
warnings.filterwarnings('ignore')


from ultralytics import YOLO
# model = YOLO("yolov8n.pt")
model = YOLO("yolov8s.pt")
results = model.train(data="yolo-dataset/yolo.yaml", epochs=30, imgsz=1080, batch=16)

這是baseline的訓練日誌

這是最佳化以後的訓練日誌

可以看到:
泛化能力(dfl_loss)和準確性(cls_loss)都有提高

相關文章