Scaled-YOLOv4

參考

環境建置

改新的環境測試

安裝AlexeyAB/darknet

常見套件

sudo apt update && \
sudo apt-get install git && \
sudo apt install python3-opencv && \
sudo apt-get install python3-bs4 && \
sudo apt install libopencv-dev
# cuDNN 7.6.5, python 3.6.9, torch 1.6.0, torchvision 0.7.1 in gcp
conda update conda && \
conda env list && \
source activate base && \
pip install torch==1.6.0+cu101 torchvision==0.7.0+cu101 -f https://download.pytorch.org/whl/torch_stable.html

安裝 mish cuda

pip3 install git+https://github.com/JunnYu/mish-cuda.git

建立工作目錄

mkdir YOLOv4-CSP
cd YOLOv4-CSP

下載 yolov4-csp

sudo apt install subversion
svn checkout https://github.com/WongKinYiu/ScaledYOLOv4/branches/yolov4-csp

準備資料集

使用 Kaggle 的口罩資料集

pip3 install kaggle

建立 kaggle_api_token.py

import json
import os

api_token = {"username":"<user>","key":"<user_key>"}

if not os.path.exists("/home/<user>/.kaggle"):
    os.makedirs("/home/<user>/.kaggle")
 
with open('/home/<user>/.kaggle/kaggle.json', 'w') as file:
    json.dump(api_token, file)

下載

kaggle datasets download -d andrewmvd/face-mask-detection
unzip face-mask-detection.zip

轉換


import os
import shutil
from bs4 import BeautifulSoup
import math

def run_convert(all_classes, train_img, train_annotation, yolo_path, write_train_txt, write_val_txt):
    now_path = os.getcwd()
    data_counter = 0

    for data_file in os.listdir(train_annotation):
        try:
            with open(os.path.join(train_annotation, data_file), 'r') as f:
                print("read file...")
                soup = BeautifulSoup(f.read(), 'xml')
                img_name = soup.select_one('filename').text

                for size in soup.select('size'):
                    img_w = int(size.select_one('width').text)
                    img_h = int(size.select_one('height').text)
                    
                img_info = []
                for obj in soup.select('object'):
                    xmin = int(obj.select_one('xmin').text)
                    xmax = int(obj.select_one('xmax').text)
                    ymin = int(obj.select_one('ymin').text)
                    ymax = int(obj.select_one('ymax').text)
                    objclass = all_classes.get(obj.select_one('name').text)

                    x = (xmin + (xmax-xmin)/2) * 1.0 / img_w
                    y = (ymin + (ymax-ymin)/2) * 1.0 / img_h
                    w = (xmax-xmin) * 1.0 / img_w
                    h = (ymax-ymin) * 1.0 / img_h
                    img_info.append(' '.join([str(objclass), str(x),str(y),str(w),str(h)]))

                # copy image to yolo path and rename
                img_path = os.path.join(train_img, img_name)
                img_format = img_name.split('.')[1]  # jpg or png
                shutil.copyfile(img_path, yolo_path + str(data_counter) + '.' + img_format)
                
                # create yolo bndbox txt
                with open(yolo_path + str(data_counter) + '.txt', 'a+') as f:
                    f.write('\n'.join(img_info))

                data_counter += 1
                    
        except Exception as e:
            print(e)
           
    print('the file is processed')

    # create train and val txt
    path = os.path.join(now_path, yolo_path)
    datasets = []
    for idx in os.listdir(yolo_path):
        if not idx.endswith('.txt'):
            idx_path = path + idx
            datasets.append(idx_path)

    len_datasets = math.floor(len(datasets)*0.8)
    with open(write_train_txt, 'a') as f:
        f.write('\n'.join(datasets[0:len_datasets]))

    with open(write_val_txt, 'a') as f:
        f.write('\n'.join(datasets[len_datasets:]))

all_classes = {'mask_weared_incorrect': 2, 'without_mask': 1, 'with_mask': 0}
train_img = "Face_Mask_data/images"
train_annotation = "Face_Mask_data/annotations"
yolo_path = "yolo_data/"
write_train_txt = 'yolov4-csp/data/train.txt'
write_val_txt = 'yolov4-csp/data/val.txt'

if not os.path.exists(yolo_path):
    os.mkdir(yolo_path)
else:
    lsdir = os.listdir(yolo_path)
    for name in lsdir:
        if name.endswith('.txt') or name.endswith('.jpg') or name.endswith('.png'):
            os.remove(os.path.join(yolo_path, name))

cfg_file = write_train_txt.split('/')[0]
if not os.path.exists(cfg_file):
    os.mkdir(cfg_file)
    
if os.path.exists(write_train_txt):
    file=open(write_train_txt, 'w')

if os.path.exists(write_val_txt):
    file=open(write_val_txt, 'w')

run_convert(all_classes, train_img, train_annotation, yolo_path, write_train_txt, write_val_txt)

報錯

read file...
Couldn't find a tree builder with the features you requested: xml. Do you need to install a parser library?

安裝

sudo apt-get install python3-bs4
cd yolov4-csp
mkdir weights

下載動作執行檔

FILEID="1NQwz47cW0NUgy7L3_xOKaNEfLoQuq3EL"
FILENAME="weights/yolov4-csp.weights"

wget --load-cookies /tmp/cookies.txt "https://docs.google.com/uc?export=download&confirm=$(wget --quiet --save-cookies /tmp/cookies.txt --keep-session-cookies --no-check-certificate 'https://docs.google.com/uc?export=download&id=${FILEID}' -O- | sed -rn 's/.*confirm=([0-9A-Za-z_]+).*/\1\n/p')&id=${FILEID}" -O ${FILENAME} && rm -rf /tmp/cookies.txt

執行

chmod +x download.sh
./download.sh

修改 cfg 中的 width, height, filters, classes

$ cp models/yolov4-csp.cfg models/yolov4-csp_416.cfg# 查看原本參數
$ sed -n -e 8p -e 9p -e 1022p -e 1029p -e 1131p -e 1138p -e 1240p -e 1247p models/yolov4-csp_416.cfg

這裡我將 width, height 修改為 416×416,而口罩資料集的 label 有 3 個類別,因此 → filters=(classes + 5)*3 = (3+5)*3 = 24

sed -i '8s/512/416/' models/yolov4-csp_416.cfg && \
sed -i '9s/512/416/' models/yolov4-csp_416.cfg && \
sed -i '1022s/255/24/' models/yolov4-csp_416.cfg && \
sed -i '1029s/80/3/' models/yolov4-csp_416.cfg && \
sed -i '1131s/255/24/' models/yolov4-csp_416.cfg && \
sed -i '1138s/80/3/' models/yolov4-csp_416.cfg && \
sed -i '1240s/255/24/' models/yolov4-csp_416.cfg && \
sed -i '1247s/80/3/' models/yolov4-csp_416.cfg && \
# 查看修改後的參數
sed -n -e 8p -e 9p -e 1022p -e 1029p -e 1131p -e 1138p -e 1240p -e 1247p models/yolov4-csp_416.cfg

修改預設 anchors 值

nano face.data
train = ./yolov4-csp/data/train.txt
val = ./yolov4-csp/data/val.txt
classes = 3

計算 anchors 值

../darknet/darknet detector calc_anchors ../YOLOv4-CSP/face.data -num_of_clusters 9 -width 416 -height 416 -showpause
# 輸出: Saving anchors to the file: anchors.txt 
anchors =   8, 15,  15, 27,  24, 39,  33, 58,  69, 56,  47, 85,  73,123, 131,127, 156,190
  • 更改 anchors 值
# 查看原本 anchors 值
cd ./yolov4-csp
sed -n -e 1028p -e 1137p -e 1246p models/yolov4-csp_416.cfg
anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401

下指令修改

sed -i '1028s/ 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401/8, 15,  15, 27,  24, 39,  33, 58,  69, 56,  47, 85,  73,123, 131,127, 156,190/' models/yolov4-csp_416.cfg && \
sed -i '1137s/ 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401/8, 15,  15, 27,  24, 39,  33, 58,  69, 56,  47, 85,  73,123, 131,127, 156,190/' models/yolov4-csp_416.cfg && \
sed -i '1246s/ 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401/8, 15,  15, 27,  24, 39,  33, 58,  69, 56,  47, 85,  73,123, 131,127, 156,190/' models/yolov4-csp_416.cfg

訓練模型

安裝需要的依賴庫

pip3 install pyyaml tqdm matplotlib scipy

建立 face.yaml,並修改其內容

cd yolov4-csp
cp data/coco.yaml data/face.yaml

修改 face.yaml

train: data/train.txt
val: data/val.txt

# number of classes
nc: 3

# class names
names: ['with_mask', 'without_mask', 'mask_weared_incorrect']

建立 face.names,並修改其內容

with_mask
without_mask
mask_weared_incorrect

執行訓練

python3 train.py --device 0 --batch-size 4 --data data/face.yaml --cfg models/yolov4-csp_416.cfg --weights ‘’ --name yolov4-csp
usr/bin/env /usr/bin/python3 /home/ubuntu/.vscode-server/extensions/ms-python.python-2021.1.502429796/pythonFiles/lib/python/debugpy/launcher 34579 -- train.py --device 0 --batch-size 4 --data data/face.yaml --cfg models/yolov4-csp_416.cfg --name yolov4-csp --weights \'\' 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *